diff -Nru bouncycastle-1.55/ant/bc+-build.xml bouncycastle-1.56/ant/bc+-build.xml --- bouncycastle-1.55/ant/bc+-build.xml 2016-08-18 02:57:31.000000000 +0000 +++ bouncycastle-1.56/ant/bc+-build.xml 2016-12-21 09:46:30.000000000 +0000 @@ -43,6 +43,12 @@ + + + + + + @@ -320,6 +326,8 @@ + + @@ -430,6 +438,8 @@ + + @@ -530,6 +540,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -863,6 +917,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru bouncycastle-1.55/ant/jdk14.xml bouncycastle-1.56/ant/jdk14.xml --- bouncycastle-1.55/ant/jdk14.xml 2015-12-28 23:21:24.000000000 +0000 +++ bouncycastle-1.56/ant/jdk14.xml 2016-08-21 00:02:06.000000000 +0000 @@ -31,7 +31,6 @@ - diff -Nru bouncycastle-1.55/ant/jdk15+.xml bouncycastle-1.56/ant/jdk15+.xml --- bouncycastle-1.55/ant/jdk15+.xml 2014-07-22 10:37:04.000000000 +0000 +++ bouncycastle-1.56/ant/jdk15+.xml 2016-12-16 23:35:51.000000000 +0000 @@ -37,6 +37,11 @@ + + + + + @@ -86,9 +91,11 @@ + + diff -Nru bouncycastle-1.55/bc-build.properties bouncycastle-1.56/bc-build.properties --- bouncycastle-1.55/bc-build.properties 2016-08-17 04:58:34.000000000 +0000 +++ bouncycastle-1.56/bc-build.properties 2016-12-22 09:08:44.000000000 +0000 @@ -1,8 +1,8 @@ -release.suffix: 155 -release.name: 1.55 -release.version: 1.55.0 -release.debug: false +release.suffix: 156 +release.name: 1.56 +release.version: 1.56.0 +release.debug: true mail.jar.home: /opt/javamail/mail.jar activation.jar.home: /opt/jaf/activation.jar diff -Nru bouncycastle-1.55/build1-1 bouncycastle-1.56/build1-1 --- bouncycastle-1.55/build1-1 2015-12-29 01:39:18.000000000 +0000 +++ bouncycastle-1.56/build1-1 2016-12-20 01:53:07.000000000 +0000 @@ -112,10 +112,10 @@ rm org/bouncycastle/jce/provider/test/DetDSATest.java rm org/bouncycastle/jce/provider/test/AEADTest.java rm -rf org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java - rm -rf org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java rm -rf org/bouncycastle/jcajce/provider/config/PKCS12StoreParameter.java rm -rf org/bouncycastle/jcajce/provider/test/PrivateConstructorTest.java rm -rf org/bouncycastle/jcajce/provider/test/ECAlgorithmParametersTest.java + rm -rf org/bouncycastle/jcajce/provider/test/RandomTest.java rm org/bouncycastle/asn1/test/GetInstanceTest.java rm org/bouncycastle/asn1/test/ASN1SequenceParserTest.java rm org/bouncycastle/asn1/test/OctetStringTest.java @@ -124,6 +124,7 @@ rm -rf org/bouncycastle/jcajce/provider/asymmetric/dstu rm -rf org/bouncycastle/jcajce/provider/asymmetric/DSTU*.java rm -rf org/bouncycastle/jcajce/provider/asymmetric/util/EC5*.java + rm -rf org/bouncycastle/jcajce/provider/drbg rm org/bouncycastle/asn1/test/EnumeratedTest.java rm -rf org/bouncycastle/pqc/jcajce rm -r org/bouncycastle/crypto/test/speedy @@ -377,15 +378,16 @@ (cd src/javax/crypto; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip *.java */*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip asn1/*.java) + (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip asn1/[bx]*/*.java) + (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip asn1/[pc]*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip crypto/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip *.java pqc/*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip u*/*.java ) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip [jk]*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip [lmn]*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip asn1/*.java) - (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip asn1/x*/*.java) - (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip asn1/c*/*.java) - (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip asn1/[abdefghijklmnopqrstuvwyz]*/*.java) + (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip asn1/[adefghijk]*/*.java) + (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip asn1/[lmnoqrstuvwyz]*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip asn1/*/*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip crypto/[ade]*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip crypto/[gimpsu]*/*.java) @@ -401,7 +403,8 @@ (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip jce/*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip util/*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip [abc]*/*/*/*.java) - (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip [ijm]*/*/*/*.java) + (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip j*/*/*/*.java) + (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip m*/*/*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip [ptuvx]*/*/*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src:$JDK11PATH/lib/classes.zip x509/*.java x509/*/*.java) diff -Nru bouncycastle-1.55/build1-2 bouncycastle-1.56/build1-2 --- bouncycastle-1.55/build1-2 2016-08-16 00:25:12.000000000 +0000 +++ bouncycastle-1.56/build1-2 2016-12-21 11:02:03.000000000 +0000 @@ -110,10 +110,10 @@ rm org/bouncycastle/jce/provider/test/DetDSATest.java rm org/bouncycastle/jce/provider/test/AEADTest.java rm -rf org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java - rm -rf org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java rm -rf org/bouncycastle/jcajce/provider/config/PKCS12StoreParameter.java rm -rf org/bouncycastle/jcajce/provider/test/PrivateConstructorTest.java rm -rf org/bouncycastle/jcajce/provider/test/ECAlgorithmParametersTest.java + rm -rf org/bouncycastle/jcajce/provider/test/RandomTest.java rm org/bouncycastle/asn1/test/GetInstanceTest.java rm org/bouncycastle/asn1/test/ASN1SequenceParserTest.java rm org/bouncycastle/asn1/test/OctetStringTest.java @@ -344,7 +344,8 @@ (cd src/org/bouncycastle/jce/cert; javac -d ../../../../../classes -classpath ../../../../../classes:../../../../../src *.java ) (cd src/org/bouncycastle/jcajce/provider; javac -d ../../../../../classes -classpath ../../../../../classes:../../../../../src [abcis]*/*.java [abcis]*/*/*.java ) - (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src *.java [abci]*/*.java [abci]*/*/*.java [abci]*/*/*/*.java ) + (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src *.java a*/*.java a*/*/*.java a*/*/*/*.java ) + (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src *.java [bci]*/*.java [bci]*/*/*.java [bci]*/*/*/*.java ) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src [jmop]*/*.java [jmop]*/*/*.java [jmop]*/*/*/*.java [jmop]*/*/*/*/*.java) (cd src/org/bouncycastle; javac -d ../../../classes -classpath ../../../classes:../../../src [tuvx]*/*.java [tuvx]*/*/*.java [tuvx]*/*/*/*.java) diff -Nru bouncycastle-1.55/build.gradle bouncycastle-1.56/build.gradle --- bouncycastle-1.55/build.gradle 2015-08-23 06:43:28.000000000 +0000 +++ bouncycastle-1.56/build.gradle 2016-11-13 00:30:06.000000000 +0000 @@ -41,7 +41,7 @@ sourceCompatibility = 1.5 targetCompatibility = 1.5 - version = '1.52' + version = '1.56-SNAPSHOT' test { systemProperty 'bc.test.data.home', bcTestDataHome @@ -52,7 +52,7 @@ } } -test.dependsOn([':core:test', ':prov:test', ':pkix:test', ':mail:test', 'pg:test']) +test.dependsOn([':core:test', ':prov:test', ':tls:test', ':pkix:test', ':mail:test', 'pg:test']) cobertura { coverageDirs = [ @@ -60,7 +60,8 @@ "${rootProject.projectDir}/mail/build/classes/main", "${rootProject.projectDir}/pg/build/classes/main", "${rootProject.projectDir}/pkix/build/classes/main", - "${rootProject.projectDir}/prov/build/classes/main" + "${rootProject.projectDir}/prov/build/classes/main", + "${rootProject.projectDir}/tls/build/classes/main", ] coverageSourceDirs = [ "${rootProject.projectDir}/core/src/main/java", @@ -68,6 +69,7 @@ "${rootProject.projectDir}/pg/src/main/java", "${rootProject.projectDir}/pkix/src/main/java", "${rootProject.projectDir}/prov/src/main/java", + "${rootProject.projectDir}/tls/src/main/java", ] coverageMergeDatafiles = [ file("${rootProject.projectDir}/core/build/cobertura/cobertura.ser"), @@ -75,6 +77,7 @@ file("${rootProject.projectDir}/pg/build/cobertura/cobertura.ser"), file("${rootProject.projectDir}/pkix/build/cobertura/cobertura.ser"), file("${rootProject.projectDir}/prov/build/cobertura/cobertura.ser"), + file("${rootProject.projectDir}/tls/build/cobertura/cobertura.ser"), ] auxiliaryClasspath += files("${rootProject.projectDir}/core/build/classes/main") coverageFormats = ['html', 'xml'] diff -Nru bouncycastle-1.55/CONTRIBUTORS.html bouncycastle-1.56/CONTRIBUTORS.html --- bouncycastle-1.55/CONTRIBUTORS.html 2016-08-20 00:55:56.000000000 +0000 +++ bouncycastle-1.56/CONTRIBUTORS.html 2016-12-23 04:32:48.000000000 +0000 @@ -6,6 +6,14 @@

Donors

+The following people and organisations donated financially to help with the release of 1.56: +
+DidiSoft, Cotiviti, Atanas Krachev, Encryptomatic LLC, LogicalAnswersIncSupporter +

+

+We also wish to acknowledge financial support from the Core Infrastructure Initiative towards developing the TLS API and JSSE provider. +

+

The following people and organisations donated financially to help with the release of 1.55:
Digistamp, RAM NAG @@ -32,7 +40,7 @@

Organisations

    -
  • Holders of Crypto Workshop Support Contracts. Over 100 hours of consulting time left over from these has been contributed back to working on the Bouncy Castle APIs. You know who you are!
  • +
  • Holders of Crypto Workshop Support Contracts. Without the consulting time left over from support contracts being contributed back to working on the Bouncy Castle APIs, progress would be impossible. You know who you are!
  • Atlassian Software Systems donation of Confluence and JIRA licences.
  • Grier Forensics, for collaborating in the development of the S/MIME Toolkit and DANE SMIMEA functionality.
  • TU-Darmstadt, Computer Science Department, RBG, for the initial @@ -408,7 +416,7 @@
  • Sebastian Oerding <sebastian.oerding@robotron.de> Fixes to toString() in x509.CertificatePolicies.
  • Kai Kramer <kai.kramer@gmail.com> Code to deal with orphaned chain certificates in the PKCS#12 KeyStore.
  • Benoit Charles <benoit.charles@opentrust.com> Fix for IES data length check on decryption.
  • -
  • Niko <nfink95@gmail.com> fix to cast issue in getOutputSize() for ECIES.
  • +
  • Niko <nfink95@gmail.com> fix to cast issue in getOutputSize() for ECIES.
  • akwizgran<https://github.com/akwizgran> Fixed clone of key in Blake2bDgest copy constructor, blake2b reset issue for varient keys.
  • Matthias Edelhoff <Matthias.Edelhoff@cryptovision.com> BasicConstraintsValidation pathlen fix in PKIX certpath classes.
  • Lukasz Deputat <lukasz.deputat@gmail.com> Fixed bugs in TlsUtils read methods [#BJA-592].
  • @@ -417,6 +425,11 @@
  • Slawomir Jaranowski<https://github.com/slawekjaranowski> Patch to make cipher/hash/signature name methods in PGP internal API public.
  • Andrey Vasilyev<https://github.com/andrey-vasilyev> Initial implementation of GOST R 34.11-2012.
  • William Glanton <wglanton77@gmail.com> Fixed bug in Poly1305 [#BJA-620].
  • +
  • jdvorak001<https://github.com/jdvorak001> Speed improvements for ASN.1 ObjectIdentifier cache.
  • +
  • Joseph Naegele <jnaegele@grierforensics.com> Patch for handling multiple certificates in a DANE SMIMEA entry.
  • +
  • Andrew Bonventre<https://github.com/andybons> NullPointer patch for WNafUtil.
  • +
  • The Google Security Team (Project Wycheproof) <https://github.com/google/wycheproof> defect analysis and additional test cases for the provider.
  • +
  • The Intel Security Team <> analysis detecting the issue with AESFastEngine (CVE-2016-1000339), additional suggestions for improvement to hardening of AESEngine.
diff -Nru bouncycastle-1.55/core/hs_err_pid8578.log bouncycastle-1.56/core/hs_err_pid8578.log --- bouncycastle-1.55/core/hs_err_pid8578.log 2015-11-15 02:49:45.000000000 +0000 +++ bouncycastle-1.56/core/hs_err_pid8578.log 1970-01-01 00:00:00.000000000 +0000 @@ -1,1015 +0,0 @@ -# -# There is insufficient memory for the Java Runtime Environment to continue. -# Native memory allocation (malloc) failed to allocate 321912832 bytes for committing reserved memory. -# Possible reasons: -# The system is out of physical RAM or swap space -# In 32 bit mode, the process size limit was hit -# Possible solutions: -# Reduce memory load on the system -# Increase physical memory or swap space -# Check if swap backing store is full -# Use 64 bit Java on a 64 bit OS -# Decrease Java heap size (-Xmx/-Xms) -# Decrease number of Java threads -# Decrease Java thread stack sizes (-Xss) -# Set larger code cache with -XX:ReservedCodeCacheSize= -# This output file may be truncated or incomplete. -# -# Out of Memory Error (os_linux.cpp:2827), pid=8578, tid=140272193365760 -# -# JRE version: OpenJDK Runtime Environment (7.0_85-b01) (build 1.7.0_85-b01) -# Java VM: OpenJDK 64-Bit Server VM (24.85-b03 mixed mode linux-amd64 compressed oops) -# Derivative: IcedTea 2.6.1 -# Distribution: Ubuntu 14.04 LTS, package 7u85-2.6.1-5ubuntu0.14.04.1 -# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again -# - ---------------- T H R E A D --------------- - -Current thread (0x00007f93b407e800): VMThread [stack: 0x00007f93aa31e000,0x00007f93aa41f000] [id=8592] - -Stack: [0x00007f93aa31e000,0x00007f93aa41f000], sp=0x00007f93aa41d490, free space=1021k -Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) -V [libjvm.so+0x953d45] VMError::report_and_die()+0x175 -V [libjvm.so+0x48fd24] report_vm_out_of_memory(char const*, int, unsigned long, char const*)+0x74 -V [libjvm.so+0x7cf91b] os::pd_commit_memory(char*, unsigned long, unsigned long, bool)+0xeb -V [libjvm.so+0x7ca3df] os::commit_memory(char*, unsigned long, unsigned long, bool)+0x1f -V [libjvm.so+0x83db6b] PSVirtualSpace::expand_by(unsigned long)+0x5b -V [libjvm.so+0x83e9d0] PSYoungGen::resize_generation(unsigned long, unsigned long)+0xb0 -V [libjvm.so+0x83f0bb] PSYoungGen::resize(unsigned long, unsigned long)+0x1b -V [libjvm.so+0x83b2f8] PSScavenge::invoke_no_policy()+0xd68 -V [libjvm.so+0x83bb68] PSScavenge::invoke()+0x38 -V [libjvm.so+0x7f2123] ParallelScavengeHeap::failed_mem_allocate(unsigned long)+0x63 -V [libjvm.so+0x955744] VM_ParallelGCFailedAllocation::doit()+0x84 -V [libjvm.so+0x959847] VM_Operation::evaluate()+0x47 -V [libjvm.so+0x958308] VMThread::evaluate_operation(VM_Operation*)+0x318 -V [libjvm.so+0x958769] VMThread::loop()+0x219 -V [libjvm.so+0x958bb2] VMThread::run()+0x72 -V [libjvm.so+0x7cc7e2] java_start(Thread*)+0xf2 - -VM_Operation (0x00007f93a3962a90): ParallelGCFailedAllocation, mode: safepoint, requested by thread 0x00007f93b49d5800 - - ---------------- P R O C E S S --------------- - -Java Threads: ( => current thread ) - 0x00007f93b49fe000 JavaThread "/0:0:0:0:0:0:0:1:39667 to /0:0:0:0:0:0:0:1%1:33006 workers Thread 3" [_thread_in_native, id=8609, stack(0x00007f93a3663000,0x00007f93a3764000)] - 0x00007f93b49fd000 JavaThread "/0:0:0:0:0:0:0:1:39667 to /0:0:0:0:0:0:0:1%1:33006 workers Thread 2" [_thread_blocked, id=8608, stack(0x00007f93a3764000,0x00007f93a3865000)] - 0x00007f93b49d5800 JavaThread "Test worker" [_thread_blocked, id=8607, stack(0x00007f93a3865000,0x00007f93a3966000)] - 0x00007f93b4126000 JavaThread "Service Thread" daemon [_thread_blocked, id=8602, stack(0x00007f93a807c000,0x00007f93a817d000)] - 0x00007f93b4123800 JavaThread "C2 CompilerThread1" daemon [_thread_blocked, id=8601, stack(0x00007f93a817d000,0x00007f93a827e000)] - 0x00007f93b411f000 JavaThread "C2 CompilerThread0" daemon [_thread_blocked, id=8600, stack(0x00007f93a827e000,0x00007f93a837f000)] - 0x00007f93b4121000 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=8599, stack(0x00007f93a837f000,0x00007f93a8480000)] - 0x00007f93b4085000 JavaThread "Finalizer" daemon [_thread_blocked, id=8594, stack(0x00007f93aa11c000,0x00007f93aa21d000)] - 0x00007f93b4083000 JavaThread "Reference Handler" daemon [_thread_blocked, id=8593, stack(0x00007f93aa21d000,0x00007f93aa31e000)] - 0x00007f93b400a800 JavaThread "main" [_thread_blocked, id=8583, stack(0x00007f93bc541000,0x00007f93bc642000)] - -Other Threads: -=>0x00007f93b407e800 VMThread [stack: 0x00007f93aa31e000,0x00007f93aa41f000] [id=8592] - 0x00007f93b4138800 WatcherThread [stack: 0x00007f93a3eff000,0x00007f93a4000000] [id=8603] - -VM state:at safepoint (normal execution) - -VM Mutex/Monitor currently owned by a thread: ([mutex/lock_event]) -[0x00007f93b4006b80] Threads_lock - owner thread: 0x00007f93b407e800 -[0x00007f93b4007080] Heap_lock - owner thread: 0x00007f93b49d5800 - -Heap - PSYoungGen total 525824K, used 5606K [0x00000007ace80000, 0x00000007cd580000, 0x0000000800000000) - eden space 520192K, 0% used [0x00000007ace80000,0x00000007ace80000,0x00000007cca80000) - from space 5632K, 99% used [0x00000007cca80000,0x00000007ccff9b00,0x00000007cd000000) - to space 5632K, 0% used [0x00000007cd000000,0x00000007cd000000,0x00000007cd580000) - ParOldGen total 169984K, used 2694K [0x0000000706c00000, 0x0000000711200000, 0x00000007ace80000) - object space 169984K, 1% used [0x0000000706c00000,0x0000000706ea1898,0x0000000711200000) - PSPermGen total 21504K, used 19864K [0x00000006fc600000, 0x00000006fdb00000, 0x0000000706c00000) - object space 21504K, 92% used [0x00000006fc600000,0x00000006fd9660f8,0x00000006fdb00000) - -Card table byte_map: [0x00007f93b895d000,0x00007f93b917b000] byte_map_base: 0x00007f93b517a000 - -Polling page: 0x00007f93bc663000 - -Code Cache [0x00007f93b1000000, 0x00007f93b1270000, 0x00007f93b4000000) - total_blobs=960 nmethods=591 adapters=322 free_code_cache=47128Kb largest_free_block=48179072 - -Compilation events (10 events): -Event: 14.540 Thread 0x00007f93b4123800 719 java.math.BigInteger::oddModPow (850 bytes) -Event: 14.599 Thread 0x00007f93b4123800 nmethod 719 0x00007f93b1198250 code [0x00007f93b1198540, 0x00007f93b119a9c8] -Event: 14.628 Thread 0x00007f93b411f000 720 org.bouncycastle.crypto.digests.SHA1Digest::processWord (212 bytes) -Event: 14.630 Thread 0x00007f93b411f000 nmethod 720 0x00007f93b1166650 code [0x00007f93b11667c0, 0x00007f93b11669a8] -Event: 15.019 Thread 0x00007f93b4123800 722 org.bouncycastle.crypto.digests.GeneralDigest::update (498 bytes) -Event: 15.047 Thread 0x00007f93b4123800 nmethod 722 0x00007f93b1183d50 code [0x00007f93b1183f60, 0x00007f93b1184e18] -Event: 15.390 Thread 0x00007f93b411f000 723 org.bouncycastle.crypto.digests.SHA224Digest::processBlock (1549 bytes) -Event: 15.417 Thread 0x00007f93b411f000 nmethod 723 0x00007f93b1196d50 code [0x00007f93b1196f20, 0x00007f93b1198138] -Event: 15.417 Thread 0x00007f93b4123800 724 org.bouncycastle.crypto.digests.SHA224Digest::reset (269 bytes) -Event: 15.424 Thread 0x00007f93b4123800 nmethod 724 0x00007f93b11febd0 code [0x00007f93b11fed80, 0x00007f93b11ff238] - -GC Heap History (10 events): -Event: 3.730 GC heap after -Heap after GC invocations=4 (full 0): - PSYoungGen total 140288K, used 2832K [0x00000007ace80000, 0x00000007b6180000, 0x0000000800000000) - eden space 130048K, 0% used [0x00000007ace80000,0x00000007ace80000,0x00000007b4d80000) - from space 10240K, 27% used [0x00000007b5780000,0x00000007b5a44010,0x00000007b6180000) - to space 10240K, 0% used [0x00000007b4d80000,0x00000007b4d80000,0x00000007b5780000) - ParOldGen total 169984K, used 32K [0x0000000706c00000, 0x0000000711200000, 0x00000007ace80000) - object space 169984K, 0% used [0x0000000706c00000,0x0000000706c08000,0x0000000711200000) - PSPermGen total 21504K, used 10377K [0x00000006fc600000, 0x00000006fdb00000, 0x0000000706c00000) - object space 21504K, 48% used [0x00000006fc600000,0x00000006fd0225a8,0x00000006fdb00000) -} -Event: 4.867 GC heap before -{Heap before GC invocations=5 (full 0): - PSYoungGen total 140288K, used 132880K [0x00000007ace80000, 0x00000007b6180000, 0x0000000800000000) - eden space 130048K, 100% used [0x00000007ace80000,0x00000007b4d80000,0x00000007b4d80000) - from space 10240K, 27% used [0x00000007b5780000,0x00000007b5a44010,0x00000007b6180000) - to space 10240K, 0% used [0x00000007b4d80000,0x00000007b4d80000,0x00000007b5780000) - ParOldGen total 169984K, used 32K [0x0000000706c00000, 0x0000000711200000, 0x00000007ace80000) - object space 169984K, 0% used [0x0000000706c00000,0x0000000706c08000,0x0000000711200000) - PSPermGen total 21504K, used 10503K [0x00000006fc600000, 0x00000006fdb00000, 0x0000000706c00000) - object space 21504K, 48% used [0x00000006fc600000,0x00000006fd041ed0,0x00000006fdb00000) -Event: 4.897 GC heap after -Heap after GC invocations=5 (full 0): - PSYoungGen total 140288K, used 2976K [0x00000007ace80000, 0x00000007bd680000, 0x0000000800000000) - eden space 130048K, 0% used [0x00000007ace80000,0x00000007ace80000,0x00000007b4d80000) - from space 10240K, 29% used [0x00000007b4d80000,0x00000007b50682f8,0x00000007b5780000) - to space 5120K, 0% used [0x00000007bd180000,0x00000007bd180000,0x00000007bd680000) - ParOldGen total 169984K, used 40K [0x0000000706c00000, 0x0000000711200000, 0x00000007ace80000) - object space 169984K, 0% used [0x0000000706c00000,0x0000000706c0a000,0x0000000711200000) - PSPermGen total 21504K, used 10503K [0x00000006fc600000, 0x00000006fdb00000, 0x0000000706c00000) - object space 21504K, 48% used [0x00000006fc600000,0x00000006fd041ed0,0x00000006fdb00000) -} -Event: 5.345 GC heap before -{Heap before GC invocations=6 (full 0): - PSYoungGen total 140288K, used 133024K [0x00000007ace80000, 0x00000007bd680000, 0x0000000800000000) - eden space 130048K, 100% used [0x00000007ace80000,0x00000007b4d80000,0x00000007b4d80000) - from space 10240K, 29% used [0x00000007b4d80000,0x00000007b50682f8,0x00000007b5780000) - to space 5120K, 0% used [0x00000007bd180000,0x00000007bd180000,0x00000007bd680000) - ParOldGen total 169984K, used 40K [0x0000000706c00000, 0x0000000711200000, 0x00000007ace80000) - object space 169984K, 0% used [0x0000000706c00000,0x0000000706c0a000,0x0000000711200000) - PSPermGen total 21504K, used 10505K [0x00000006fc600000, 0x00000006fdb00000, 0x0000000706c00000) - object space 21504K, 48% used [0x00000006fc600000,0x00000006fd0424f0,0x00000006fdb00000) -Event: 5.389 GC heap after -Heap after GC invocations=6 (full 0): - PSYoungGen total 265216K, used 2800K [0x00000007ace80000, 0x00000007bd680000, 0x0000000800000000) - eden space 260096K, 0% used [0x00000007ace80000,0x00000007ace80000,0x00000007bcc80000) - from space 5120K, 54% used [0x00000007bd180000,0x00000007bd43c308,0x00000007bd680000) - to space 5120K, 0% used [0x00000007bcc80000,0x00000007bcc80000,0x00000007bd180000) - ParOldGen total 169984K, used 48K [0x0000000706c00000, 0x0000000711200000, 0x00000007ace80000) - object space 169984K, 0% used [0x0000000706c00000,0x0000000706c0c000,0x0000000711200000) - PSPermGen total 21504K, used 10505K [0x00000006fc600000, 0x00000006fdb00000, 0x0000000706c00000) - object space 21504K, 48% used [0x00000006fc600000,0x00000006fd0424f0,0x00000006fdb00000) -} -Event: 5.986 GC heap before -{Heap before GC invocations=7 (full 0): - PSYoungGen total 265216K, used 262896K [0x00000007ace80000, 0x00000007bd680000, 0x0000000800000000) - eden space 260096K, 100% used [0x00000007ace80000,0x00000007bcc80000,0x00000007bcc80000) - from space 5120K, 54% used [0x00000007bd180000,0x00000007bd43c308,0x00000007bd680000) - to space 5120K, 0% used [0x00000007bcc80000,0x00000007bcc80000,0x00000007bd180000) - ParOldGen total 169984K, used 48K [0x0000000706c00000, 0x0000000711200000, 0x00000007ace80000) - object space 169984K, 0% used [0x0000000706c00000,0x0000000706c0c000,0x0000000711200000) - PSPermGen total 21504K, used 10511K [0x00000006fc600000, 0x00000006fdb00000, 0x0000000706c00000) - object space 21504K, 48% used [0x00000006fc600000,0x00000006fd043da0,0x00000006fdb00000) -Event: 5.995 GC heap after -Heap after GC invocations=7 (full 0): - PSYoungGen total 265216K, used 192K [0x00000007ace80000, 0x00000007cd580000, 0x0000000800000000) - eden space 260096K, 0% used [0x00000007ace80000,0x00000007ace80000,0x00000007bcc80000) - from space 5120K, 3% used [0x00000007bcc80000,0x00000007bccb0000,0x00000007bd180000) - to space 5632K, 0% used [0x00000007cd000000,0x00000007cd000000,0x00000007cd580000) - ParOldGen total 169984K, used 2356K [0x0000000706c00000, 0x0000000711200000, 0x00000007ace80000) - object space 169984K, 1% used [0x0000000706c00000,0x0000000706e4d0d8,0x0000000711200000) - PSPermGen total 21504K, used 10511K [0x00000006fc600000, 0x00000006fdb00000, 0x0000000706c00000) - object space 21504K, 48% used [0x00000006fc600000,0x00000006fd043da0,0x00000006fdb00000) -} -Event: 6.707 GC heap before -{Heap before GC invocations=8 (full 0): - PSYoungGen total 265216K, used 260288K [0x00000007ace80000, 0x00000007cd580000, 0x0000000800000000) - eden space 260096K, 100% used [0x00000007ace80000,0x00000007bcc80000,0x00000007bcc80000) - from space 5120K, 3% used [0x00000007bcc80000,0x00000007bccb0000,0x00000007bd180000) - to space 5632K, 0% used [0x00000007cd000000,0x00000007cd000000,0x00000007cd580000) - ParOldGen total 169984K, used 2356K [0x0000000706c00000, 0x0000000711200000, 0x00000007ace80000) - object space 169984K, 1% used [0x0000000706c00000,0x0000000706e4d0d8,0x0000000711200000) - PSPermGen total 21504K, used 11596K [0x00000006fc600000, 0x00000006fdb00000, 0x0000000706c00000) - object space 21504K, 53% used [0x00000006fc600000,0x00000006fd153060,0x00000006fdb00000) -Event: 6.775 GC heap after -Heap after GC invocations=8 (full 0): - PSYoungGen total 525824K, used 672K [0x00000007ace80000, 0x00000007cd580000, 0x0000000800000000) - eden space 520192K, 0% used [0x00000007ace80000,0x00000007ace80000,0x00000007cca80000) - from space 5632K, 11% used [0x00000007cd000000,0x00000007cd0a8000,0x00000007cd580000) - to space 5632K, 0% used [0x00000007cca80000,0x00000007cca80000,0x00000007cd000000) - ParOldGen total 169984K, used 2412K [0x0000000706c00000, 0x0000000711200000, 0x00000007ace80000) - object space 169984K, 1% used [0x0000000706c00000,0x0000000706e5b0d8,0x0000000711200000) - PSPermGen total 21504K, used 11596K [0x00000006fc600000, 0x00000006fdb00000, 0x0000000706c00000) - object space 21504K, 53% used [0x00000006fc600000,0x00000006fd153060,0x00000006fdb00000) -} -Event: 18.593 GC heap before -{Heap before GC invocations=9 (full 0): - PSYoungGen total 525824K, used 520864K [0x00000007ace80000, 0x00000007cd580000, 0x0000000800000000) - eden space 520192K, 100% used [0x00000007ace80000,0x00000007cca80000,0x00000007cca80000) - from space 5632K, 11% used [0x00000007cd000000,0x00000007cd0a8000,0x00000007cd580000) - to space 5632K, 0% used [0x00000007cca80000,0x00000007cca80000,0x00000007cd000000) - ParOldGen total 169984K, used 2412K [0x0000000706c00000, 0x0000000711200000, 0x00000007ace80000) - object space 169984K, 1% used [0x0000000706c00000,0x0000000706e5b0d8,0x0000000711200000) - PSPermGen total 21504K, used 19864K [0x00000006fc600000, 0x00000006fdb00000, 0x0000000706c00000) - object space 21504K, 92% used [0x00000006fc600000,0x00000006fd9660f8,0x00000006fdb00000) - -Deoptimization events (10 events): -Event: 11.817 Thread 0x00007f93b49d5800 Uncommon trap: reason=unstable_if action=reinterpret pc=0x00007f93b10a5444 method=java.math.BigInteger.shiftRight(I)Ljava/math/BigInteger; @ 231 -Event: 11.818 Thread 0x00007f93b49d5800 Uncommon trap: reason=unstable_if action=reinterpret pc=0x00007f93b1125ae8 method=java.math.MutableBigInteger.normalize()V @ 40 -Event: 11.833 Thread 0x00007f93b49d5800 Uncommon trap: reason=unstable_if action=reinterpret pc=0x00007f93b1118c3c method=java.math.MutableBigInteger.normalize()V @ 40 -Event: 14.154 Thread 0x00007f93b49d5800 Uncommon trap: reason=unstable_if action=reinterpret pc=0x00007f93b111b580 method=org.bouncycastle.util.Arrays.areEqual([B[B)Z @ 175 -Event: 14.420 Thread 0x00007f93b49d5800 Uncommon trap: reason=unstable_if action=reinterpret pc=0x00007f93b11c4cbc method=java.math.BigInteger.oddModPow(Ljava/math/BigInteger;Ljava/math/BigInteger;)Ljava/math/BigInteger; @ 449 -Event: 15.011 Thread 0x00007f93b49d5800 Uncommon trap: reason=bimorphic action=maybe_recompile pc=0x00007f93b10f095c method=org.bouncycastle.crypto.digests.GeneralDigest.update([BII)V @ 339 -Event: 15.015 Thread 0x00007f93b49d5800 Uncommon trap: reason=bimorphic action=maybe_recompile pc=0x00007f93b10f095c method=org.bouncycastle.crypto.digests.GeneralDigest.update([BII)V @ 339 -Event: 15.019 Thread 0x00007f93b49d5800 Uncommon trap: reason=bimorphic action=maybe_recompile pc=0x00007f93b10f095c method=org.bouncycastle.crypto.digests.GeneralDigest.update([BII)V @ 339 -Event: 15.019 Thread 0x00007f93b49d5800 Uncommon trap: reason=bimorphic action=maybe_recompile pc=0x00007f93b10f095c method=org.bouncycastle.crypto.digests.GeneralDigest.update([BII)V @ 339 -Event: 18.584 Thread 0x00007f93b49d5800 Uncommon trap: reason=unstable_if action=reinterpret pc=0x00007f93b10ed894 method=java.math.MutableBigInteger.mul(ILjava/math/MutableBigInteger;)V @ 125 - -Internal exceptions (10 events): -Event: 14.381 Thread 0x00007f93b49d5800 Threw 0x00000007c5e38b58 at /build/openjdk-7-65SuYz/openjdk-7-7u85-2.6.1/build/openjdk/hotspot/src/share/vm/prims/jvm.cpp:1322 -Event: 14.489 Thread 0x00007f93b49d5800 Threw 0x00000007c63e53a8 at /build/openjdk-7-65SuYz/openjdk-7-7u85-2.6.1/build/openjdk/hotspot/src/share/vm/prims/jvm.cpp:1322 -Event: 14.504 Thread 0x00007f93b49d5800 Threw 0x00000007c63f3640 at /build/openjdk-7-65SuYz/openjdk-7-7u85-2.6.1/build/openjdk/hotspot/src/share/vm/prims/jvm.cpp:1322 -Event: 14.514 Thread 0x00007f93b49d5800 Threw 0x00000007c63f8338 at /build/openjdk-7-65SuYz/openjdk-7-7u85-2.6.1/build/openjdk/hotspot/src/share/vm/prims/jvm.cpp:1322 -Event: 14.639 Thread 0x00007f93b49d5800 Threw 0x00000007c66b85c8 at /build/openjdk-7-65SuYz/openjdk-7-7u85-2.6.1/build/openjdk/hotspot/src/share/vm/prims/jvm.cpp:1322 -Event: 14.799 Thread 0x00007f93b49d5800 Threw 0x00000007c66c6a98 at /build/openjdk-7-65SuYz/openjdk-7-7u85-2.6.1/build/openjdk/hotspot/src/share/vm/prims/jvm.cpp:1322 -Event: 14.811 Thread 0x00007f93b49d5800 Threw 0x00000007c66cb9d0 at /build/openjdk-7-65SuYz/openjdk-7-7u85-2.6.1/build/openjdk/hotspot/src/share/vm/prims/jvm.cpp:1322 -Event: 14.817 Thread 0x00007f93b49d5800 Threw 0x00000007c66e93b8 at /build/openjdk-7-65SuYz/openjdk-7-7u85-2.6.1/build/openjdk/hotspot/src/share/vm/prims/jvm.cpp:1322 -Event: 14.961 Thread 0x00007f93b49d5800 Threw 0x00000007c66f62e0 at /build/openjdk-7-65SuYz/openjdk-7-7u85-2.6.1/build/openjdk/hotspot/src/share/vm/prims/jvm.cpp:1322 -Event: 18.553 Thread 0x00007f93b49d5800 Threw 0x00000007cba234c8 at /build/openjdk-7-65SuYz/openjdk-7-7u85-2.6.1/build/openjdk/hotspot/src/share/vm/prims/jvm.cpp:1322 - -Events (10 events): -Event: 15.019 Thread 0x00007f93b49d5800 DEOPT UNPACKING pc=0x00007f93b1039445 sp=0x00007f93a3962f90 mode 2 -Event: 15.019 Thread 0x00007f93b49d5800 Uncommon trap: trap_request=0xffffffc6 fr.pc=0x00007f93b10f095c -Event: 15.019 Thread 0x00007f93b49d5800 DEOPT PACKING pc=0x00007f93b10f095c sp=0x00007f93a3962fc0 -Event: 15.019 Thread 0x00007f93b49d5800 DEOPT UNPACKING pc=0x00007f93b1039445 sp=0x00007f93a3962f90 mode 2 -Event: 18.552 loading class 0x00007f934c144bd0 -Event: 18.552 loading class 0x00007f934c144bd0 done -Event: 18.584 Thread 0x00007f93b49d5800 Uncommon trap: trap_request=0xffffff75 fr.pc=0x00007f93b10ed894 -Event: 18.584 Thread 0x00007f93b49d5800 DEOPT PACKING pc=0x00007f93b10ed894 sp=0x00007f93a3962f00 -Event: 18.585 Thread 0x00007f93b49d5800 DEOPT UNPACKING pc=0x00007f93b1039445 sp=0x00007f93a3962e98 mode 2 -Event: 18.590 Executing VM operation: ParallelGCFailedAllocation - - -Dynamic libraries: -00400000-00401000 r-xp 00000000 fc:01 23729929 /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java -00600000-00601000 r--p 00000000 fc:01 23729929 /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java -00601000-00602000 rw-p 00001000 fc:01 23729929 /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java -01993000-019b4000 rw-p 00000000 00:00 0 [heap] -6fc600000-6fdb00000 rw-p 00000000 00:00 0 -6fdb00000-706c00000 rw-p 00000000 00:00 0 -706c00000-711200000 rw-p 00000000 00:00 0 -711200000-7ace80000 rw-p 00000000 00:00 0 -7ace80000-7cd580000 rw-p 00000000 00:00 0 -7e0880000-800000000 rw-p 00000000 00:00 0 -7f933c000000-7f933c056000 rw-p 00000000 00:00 0 -7f933c056000-7f9340000000 ---p 00000000 00:00 0 -7f9344000000-7f9344069000 rw-p 00000000 00:00 0 -7f9344069000-7f9348000000 ---p 00000000 00:00 0 -7f9348000000-7f934812e000 rw-p 00000000 00:00 0 -7f934812e000-7f934c000000 ---p 00000000 00:00 0 -7f934c000000-7f934c40d000 rw-p 00000000 00:00 0 -7f934c40d000-7f9350000000 ---p 00000000 00:00 0 -7f9350000000-7f9350021000 rw-p 00000000 00:00 0 -7f9350021000-7f9354000000 ---p 00000000 00:00 0 -7f9354000000-7f9354021000 rw-p 00000000 00:00 0 -7f9354021000-7f9358000000 ---p 00000000 00:00 0 -7f9358000000-7f9358021000 rw-p 00000000 00:00 0 -7f9358021000-7f935c000000 ---p 00000000 00:00 0 -7f935c000000-7f935ca90000 rw-p 00000000 00:00 0 -7f935ca90000-7f9360000000 ---p 00000000 00:00 0 -7f9360000000-7f936119e000 rw-p 00000000 00:00 0 -7f936119e000-7f9364000000 ---p 00000000 00:00 0 -7f9364000000-7f9364021000 rw-p 00000000 00:00 0 -7f9364021000-7f9368000000 ---p 00000000 00:00 0 -7f9368000000-7f9368021000 rw-p 00000000 00:00 0 -7f9368021000-7f936c000000 ---p 00000000 00:00 0 -7f936c000000-7f936c021000 rw-p 00000000 00:00 0 -7f936c021000-7f9370000000 ---p 00000000 00:00 0 -7f9373e30000-7f937c000000 rw-p 00000000 00:00 0 -7f937c000000-7f937c021000 rw-p 00000000 00:00 0 -7f937c021000-7f9380000000 ---p 00000000 00:00 0 -7f9380000000-7f9380241000 rw-p 00000000 00:00 0 -7f9380241000-7f9384000000 ---p 00000000 00:00 0 -7f9384000000-7f9384021000 rw-p 00000000 00:00 0 -7f9384021000-7f9388000000 ---p 00000000 00:00 0 -7f938c000000-7f938c021000 rw-p 00000000 00:00 0 -7f938c021000-7f9390000000 ---p 00000000 00:00 0 -7f9394000000-7f9394021000 rw-p 00000000 00:00 0 -7f9394021000-7f9398000000 ---p 00000000 00:00 0 -7f9398000000-7f9398021000 rw-p 00000000 00:00 0 -7f9398021000-7f939c000000 ---p 00000000 00:00 0 -7f939c000000-7f939c021000 rw-p 00000000 00:00 0 -7f939c021000-7f93a0000000 ---p 00000000 00:00 0 -7f93a1f2c000-7f93a1fa4000 r-xp 00000000 fc:01 24117258 /usr/lib/x86_64-linux-gnu/nss/libfreebl3.so -7f93a1fa4000-7f93a21a3000 ---p 00078000 fc:01 24117258 /usr/lib/x86_64-linux-gnu/nss/libfreebl3.so -7f93a21a3000-7f93a21a5000 r--p 00077000 fc:01 24117258 /usr/lib/x86_64-linux-gnu/nss/libfreebl3.so -7f93a21a5000-7f93a21a6000 rw-p 00079000 fc:01 24117258 /usr/lib/x86_64-linux-gnu/nss/libfreebl3.so -7f93a21a6000-7f93a21aa000 rw-p 00000000 00:00 0 -7f93a21aa000-7f93a225e000 r-xp 00000000 fc:01 23724467 /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6 -7f93a225e000-7f93a245e000 ---p 000b4000 fc:01 23724467 /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6 -7f93a245e000-7f93a2460000 r--p 000b4000 fc:01 23724467 /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6 -7f93a2460000-7f93a2462000 rw-p 000b6000 fc:01 23724467 /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6 -7f93a2462000-7f93a2463000 rw-p 00000000 00:00 0 -7f93a2463000-7f93a24a3000 r-xp 00000000 fc:01 24118209 /usr/lib/x86_64-linux-gnu/nss/libsoftokn3.so -7f93a24a3000-7f93a26a3000 ---p 00040000 fc:01 24118209 /usr/lib/x86_64-linux-gnu/nss/libsoftokn3.so -7f93a26a3000-7f93a26a4000 r--p 00040000 fc:01 24118209 /usr/lib/x86_64-linux-gnu/nss/libsoftokn3.so -7f93a26a4000-7f93a26a5000 rw-p 00041000 fc:01 24118209 /usr/lib/x86_64-linux-gnu/nss/libsoftokn3.so -7f93a26a5000-7f93a26de000 r-xp 00000000 fc:01 23728669 /usr/lib/x86_64-linux-gnu/libnspr4.so -7f93a26de000-7f93a28dd000 ---p 00039000 fc:01 23728669 /usr/lib/x86_64-linux-gnu/libnspr4.so -7f93a28dd000-7f93a28de000 r--p 00038000 fc:01 23728669 /usr/lib/x86_64-linux-gnu/libnspr4.so -7f93a28de000-7f93a28df000 rw-p 00039000 fc:01 23728669 /usr/lib/x86_64-linux-gnu/libnspr4.so -7f93a28df000-7f93a28e2000 rw-p 00000000 00:00 0 -7f93a28e2000-7f93a28e5000 r-xp 00000000 fc:01 23728293 /usr/lib/x86_64-linux-gnu/libplds4.so -7f93a28e5000-7f93a2ae4000 ---p 00003000 fc:01 23728293 /usr/lib/x86_64-linux-gnu/libplds4.so -7f93a2ae4000-7f93a2ae5000 r--p 00002000 fc:01 23728293 /usr/lib/x86_64-linux-gnu/libplds4.so -7f93a2ae5000-7f93a2ae6000 rw-p 00003000 fc:01 23728293 /usr/lib/x86_64-linux-gnu/libplds4.so -7f93a2ae6000-7f93a2aea000 r-xp 00000000 fc:01 23729866 /usr/lib/x86_64-linux-gnu/libplc4.so -7f93a2aea000-7f93a2ce9000 ---p 00004000 fc:01 23729866 /usr/lib/x86_64-linux-gnu/libplc4.so -7f93a2ce9000-7f93a2cea000 r--p 00003000 fc:01 23729866 /usr/lib/x86_64-linux-gnu/libplc4.so -7f93a2cea000-7f93a2ceb000 rw-p 00004000 fc:01 23729866 /usr/lib/x86_64-linux-gnu/libplc4.so -7f93a2ceb000-7f93a2d10000 r-xp 00000000 fc:01 23727748 /usr/lib/x86_64-linux-gnu/libnssutil3.so -7f93a2d10000-7f93a2f0f000 ---p 00025000 fc:01 23727748 /usr/lib/x86_64-linux-gnu/libnssutil3.so -7f93a2f0f000-7f93a2f15000 r--p 00024000 fc:01 23727748 /usr/lib/x86_64-linux-gnu/libnssutil3.so -7f93a2f15000-7f93a2f16000 rw-p 0002a000 fc:01 23727748 /usr/lib/x86_64-linux-gnu/libnssutil3.so -7f93a2f16000-7f93a3049000 r-xp 00000000 fc:01 23730055 /usr/lib/x86_64-linux-gnu/libnss3.so -7f93a3049000-7f93a3248000 ---p 00133000 fc:01 23730055 /usr/lib/x86_64-linux-gnu/libnss3.so -7f93a3248000-7f93a324d000 r--p 00132000 fc:01 23730055 /usr/lib/x86_64-linux-gnu/libnss3.so -7f93a324d000-7f93a324f000 rw-p 00137000 fc:01 23730055 /usr/lib/x86_64-linux-gnu/libnss3.so -7f93a324f000-7f93a3250000 rw-p 00000000 00:00 0 -7f93a3250000-7f93a3260000 r-xp 00000000 fc:01 23730650 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libj2pkcs11.so -7f93a3260000-7f93a345f000 ---p 00010000 fc:01 23730650 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libj2pkcs11.so -7f93a345f000-7f93a3460000 r--p 0000f000 fc:01 23730650 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libj2pkcs11.so -7f93a3460000-7f93a3461000 rw-p 00010000 fc:01 23730650 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libj2pkcs11.so -7f93a3461000-7f93a3464000 ---p 00000000 00:00 0 -7f93a3464000-7f93a3562000 rw-p 00000000 00:00 0 -7f93a3562000-7f93a3565000 ---p 00000000 00:00 0 -7f93a3565000-7f93a3663000 rw-p 00000000 00:00 0 -7f93a3663000-7f93a3666000 ---p 00000000 00:00 0 -7f93a3666000-7f93a3764000 rw-p 00000000 00:00 0 [stack:8609] -7f93a3764000-7f93a3767000 ---p 00000000 00:00 0 -7f93a3767000-7f93a3865000 rw-p 00000000 00:00 0 [stack:8608] -7f93a3865000-7f93a3868000 ---p 00000000 00:00 0 -7f93a3868000-7f93a3966000 rw-p 00000000 00:00 0 [stack:8607] -7f93a3966000-7f93a3967000 r--s 0000a000 00:1f 16520392 /home/dgh/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-util/5.0.1/7c8caddfbd0b2d7b844f8fcc75175b9cb9cf4724/asm-util-5.0.1.jar -7f93a3989000-7f93a398a000 rw-p 00000000 00:00 0 -7f93a398a000-7f93a398c000 r--s 00018000 fc:01 23729939 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jce.jar -7f93a398c000-7f93a3996000 r--s 0005d000 00:1f 18617183 /home/dgh/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-core/1.0.13/dc6e6ce937347bd4d990fc89f4ceb469db53e45e/logback-core-1.0.13.jar -7f93a3996000-7f93a3997000 r--s 00004000 00:1f 16520442 /home/dgh/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant-launcher/1.8.3/a22bcf9438c41828b04c13b052c4886606abac2/ant-launcher-1.8.3.jar -7f93a3997000-7f93a399e000 r--s 0005e000 00:1f 16520434 /home/dgh/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-lang3/3.3.2/90a3822c38ec8c996e84c16a3477ef632cbc87a3/commons-lang3-3.3.2.jar -7f93a399e000-7f93a39a4000 r--s 0003b000 00:1f 18487211 /home/dgh/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.0.13/6b56ec752b42ccfa1415c0361fb54b1ed7ca3db6/logback-classic-1.0.13.jar -7f93a39a4000-7f93a39a7000 r--s 00025000 00:1f 16520432 /home/dgh/.gradle/caches/modules-2/files-2.1/org.mortbay.jetty/jetty-util/6.1.14/1b707d5884e35c9b97114a24aa9ee94ca531fa21/jetty-util-6.1.14.jar -7f93a39a7000-7f93a39ae000 r--s 00078000 00:1f 16520430 /home/dgh/.gradle/caches/modules-2/files-2.1/org.mortbay.jetty/jetty/6.1.14/5ded67b609e59c27e82ff61b510773d28c9bef56/jetty-6.1.14.jar -7f93a39ae000-7f93a39b1000 r--s 0001e000 00:1f 16520421 /home/dgh/.gradle/caches/modules-2/files-2.1/org.mortbay.jetty/servlet-api-2.5/6.1.14/5f07601ab7d7c85dd9e38a17c0e1b0edfbd4a191/servlet-api-2.5-6.1.14.jar -7f93a39b1000-7f93a39b4000 r--s 00018000 00:1f 16520402 /home/dgh/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant-junit/1.8.3/9f77eec4e103241602fb0cdd97b3ec3237e0bd9/ant-junit-1.8.3.jar -7f93a39b4000-7f93a39d2000 r--s 001bc000 00:1f 16520400 /home/dgh/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant/1.8.3/77c746ecab048b9839c7a8e39e55fe8636c5b11/ant-1.8.3.jar -7f93a39d2000-7f93a39d8000 r--s 00032000 00:1f 16520398 /home/dgh/.gradle/caches/modules-2/files-2.1/jaxen/jaxen/1.1.4/8c06a96cf9150ded75c28b7087ed821a93270c41/jaxen-1.1.4.jar -7f93a39d8000-7f93a39da000 r--s 0000e000 00:1f 16520396 /home/dgh/.gradle/caches/modules-2/files-2.1/oro/oro/2.0.8/5592374f834645c4ae250f4c9fbb314c9369d698/oro-2.0.8.jar -7f93a39da000-7f93a39db000 r--s 00004000 00:1f 16520394 /home/dgh/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-analysis/5.0.1/e286fbee48efacb4e7c175f7948d9d8b2ab52352/asm-analysis-5.0.1.jar -7f93a39db000-7f93a39dd000 r--s 00009000 00:1f 16520390 /home/dgh/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-commons/5.0.1/7b7147a390a93a14d2edfdcf3f7b0e87a0939c3e/asm-commons-5.0.1.jar -7f93a39dd000-7f93a39df000 r--s 00006000 00:1f 16520388 /home/dgh/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-tree/5.0.1/1b1e6e9d869acd704056d0a4223071a511c619e6/asm-tree-5.0.1.jar -7f93a39df000-7f93a39e0000 r--s 0000c000 00:1f 16394149 /home/dgh/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm/5.0.1/2fd56467a018aafe6ec6a73ccba520be4a7e1565/asm-5.0.1.jar -7f93a39e0000-7f93a39e7000 r--s 00083000 00:1f 16394147 /home/dgh/.gradle/caches/modules-2/files-2.1/net.sourceforge.cobertura/cobertura/2.1.1/eab984794b3f7d0d37736a9e5b7f790128f611b5/cobertura-2.1.1.jar -7f93a39e7000-7f93a39e9000 r--s 00005000 00:1f 19141389 /home/dgh/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.5/6b262da268f8ad9eff941b25503a9198f0a0ac93/slf4j-api-1.7.5.jar -7f93a39e9000-7f93a39eb000 r--s 00009000 00:1f 15601322 /home/dgh/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar -7f93a39eb000-7f93a39f4000 r--s 0006f000 00:1f 12983879 /home/dgh/.gradle/caches/modules-2/files-2.1/log4j/log4j/1.2.17/5af35056b4d257e4b64b9e8069c0746e8b08629f/log4j-1.2.17.jar -7f93a39f4000-7f93a39f6000 r--s 00001000 00:1f 19141353 /home/dgh/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-log4j12/1.7.5/6edffc576ce104ec769d954618764f39f0f0f10d/slf4j-log4j12-1.7.5.jar -7f93a39f6000-7f93a39fc000 r--s 00036000 00:1f 15601320 /home/dgh/.gradle/caches/modules-2/files-2.1/junit/junit/4.11/4e031bb61df09069aeb2bffb4019e7a5034a4ee0/junit-4.11.jar -7f93a39fc000-7f93a3a14000 r--s 00115000 fc:01 1051865 /opt/installs/gradle-2.1/lib/plugins/xercesImpl-2.9.1.jar -7f93a3a14000-7f93a3a1c000 r--s 00028000 fc:01 1051866 /opt/installs/gradle-2.1/lib/plugins/xml-apis-1.3.04.jar -7f93a3a1c000-7f93a3a22000 r--s 0005b000 fc:01 1051841 /opt/installs/gradle-2.1/lib/plugins/jcifs-1.3.17.jar -7f93a3a22000-7f93a3a28000 r--s 00031000 fc:01 1051813 /opt/installs/gradle-2.1/lib/plugins/httpcore-4.2.2.jar -7f93a3a28000-7f93a3a2e000 r--s 00033000 fc:01 1051780 /opt/installs/gradle-2.1/lib/plugins/commons-codec-1.6.jar -7f93a3a2e000-7f93a3a31000 r--s 0001c000 fc:01 1051853 /opt/installs/gradle-2.1/lib/plugins/nekohtml-1.9.14.jar -7f93a3a31000-7f93a3a3a000 r--s 00060000 fc:01 1051812 /opt/installs/gradle-2.1/lib/plugins/httpclient-4.2.2.jar -7f93a3a3a000-7f93a3a3c000 r--s 00007000 fc:01 1051806 /opt/installs/gradle-2.1/lib/plugins/gradle-resources-http-2.1.jar -7f93a3a3c000-7f93a3a40000 r--s 0001d000 fc:01 1051864 /opt/installs/gradle-2.1/lib/plugins/xbean-reflect-3.4.jar -7f93a3a40000-7f93a3a44000 r--s 0003d000 fc:01 1051848 /opt/installs/gradle-2.1/lib/plugins/jsch-0.1.51.jar -7f93a3a44000-7f93a3a53000 r--s 000d9000 fc:01 1051814 /opt/installs/gradle-2.1/lib/plugins/ivy-2.2.0.jar -7f93a3a53000-7f93a3a57000 r--s 0001e000 fc:01 1051817 /opt/installs/gradle-2.1/lib/plugins/jarjar-aether-impl-1.13.1.jar -7f93a3a57000-7f93a3a5a000 r--s 00027000 fc:01 1051824 /opt/installs/gradle-2.1/lib/plugins/jarjar-maven-model-3.0.4.jar -7f93a3a5a000-7f93a3a5d000 r--s 0000b000 fc:01 1051821 /opt/installs/gradle-2.1/lib/plugins/jarjar-maven-artifact-3.0.4.jar -7f93a3a5d000-7f93a3a61000 r--s 0001e000 fc:01 1051819 /opt/installs/gradle-2.1/lib/plugins/jarjar-aether-util-1.13.1.jar -7f93a3a61000-7f93a3a63000 r--s 00007000 fc:01 1051838 /opt/installs/gradle-2.1/lib/plugins/jarjar-wagon-http-shared4-2.4.jar -7f93a3a63000-7f93a3a70000 r--s 00083000 fc:01 1051823 /opt/installs/gradle-2.1/lib/plugins/jarjar-maven-core-3.0.4.jar -7f93a3a70000-7f93a3a72000 r--s 00003000 fc:01 1051818 /opt/installs/gradle-2.1/lib/plugins/jarjar-aether-spi-1.13.1.jar -7f93a3a72000-7f93a3a74000 r--s 00009000 fc:01 1051829 /opt/installs/gradle-2.1/lib/plugins/jarjar-maven-settings-builder-3.0.4.jar -7f93a3a74000-7f93a3a78000 r--s 00014000 fc:01 1051815 /opt/installs/gradle-2.1/lib/plugins/jarjar-aether-api-1.13.1.jar -7f93a3a78000-7f93a3a79000 r--s 00002000 fc:01 1051837 /opt/installs/gradle-2.1/lib/plugins/jarjar-wagon-http-2.4.jar -7f93a3a79000-7f93a3a80000 r--s 00042000 fc:01 1051822 /opt/installs/gradle-2.1/lib/plugins/jarjar-maven-compat-3.0.4.jar -7f93a3a80000-7f93a3a82000 r--s 00006000 fc:01 1051816 /opt/installs/gradle-2.1/lib/plugins/jarjar-aether-connector-wagon-1.13.1.jar -7f93a3a82000-7f93a3a84000 r--s 00000000 fc:01 1051832 /opt/installs/gradle-2.1/lib/plugins/jarjar-plexus-component-annotations-1.5.5.jar -7f93a3a84000-7f93a3a86000 r--s 00006000 fc:01 1051835 /opt/installs/gradle-2.1/lib/plugins/jarjar-plexus-sec-dispatcher-1.3.jar -7f93a3a86000-7f93a3a8b000 r--s 00022000 fc:01 1051825 /opt/installs/gradle-2.1/lib/plugins/jarjar-maven-model-builder-3.0.4.jar -7f93a3a8b000-7f93a3a8d000 r--s 0000b000 fc:01 1051826 /opt/installs/gradle-2.1/lib/plugins/jarjar-maven-plugin-api-3.0.4.jar -7f93a3a8d000-7f93a3a90000 r--s 0000a000 fc:01 1051831 /opt/installs/gradle-2.1/lib/plugins/jarjar-plexus-classworlds-2.4.jar -7f93a3a90000-7f93a3a94000 r--s 00035000 fc:01 1051836 /opt/installs/gradle-2.1/lib/plugins/jarjar-plexus-utils-2.0.6.jar -7f93a3a94000-7f93a3a96000 r--s 0000e000 fc:01 1051834 /opt/installs/gradle-2.1/lib/plugins/jarjar-plexus-interpolation-1.14.jar -7f93a3a96000-7f93a3a98000 r--s 00002000 fc:01 1051830 /opt/installs/gradle-2.1/lib/plugins/jarjar-plexus-cipher-1.7.jar -7f93a3a98000-7f93a3a9a000 r--s 0000c000 fc:01 1051839 /opt/installs/gradle-2.1/lib/plugins/jarjar-wagon-provider-api-2.4.jar -7f93a3a9a000-7f93a3a9c000 r--s 0000d000 fc:01 1051820 /opt/installs/gradle-2.1/lib/plugins/jarjar-maven-aether-provider-3.0.4.jar -7f93a3a9c000-7f93a3aa4000 r--s 00031000 fc:01 1051833 /opt/installs/gradle-2.1/lib/plugins/jarjar-plexus-container-default-1.5.5.jar -7f93a3aa4000-7f93a3aa5000 r--s 00007000 fc:01 1051827 /opt/installs/gradle-2.1/lib/plugins/jarjar-maven-repository-metadata-3.0.4.jar -7f93a3aa5000-7f93a3aa6000 r--s 0000b000 fc:01 1051828 /opt/installs/gradle-2.1/lib/plugins/jarjar-maven-settings-3.0.4.jar -7f93a3aa6000-7f93a3abe000 r--s 000ac000 fc:01 1051788 /opt/installs/gradle-2.1/lib/plugins/gradle-core-impl-2.1.jar -7f93a3abe000-7f93a3ac7000 r--s 0002a000 fc:01 790192 /opt/installs/gradle-2.1/lib/gradle-tooling-api-2.1.jar -7f93a3ac7000-7f93a3ac9000 r--s 00002000 fc:01 790190 /opt/installs/gradle-2.1/lib/gradle-open-api-2.1.jar -7f93a3ac9000-7f93a3acf000 r--s 00032000 fc:01 790200 /opt/installs/gradle-2.1/lib/jaxen-1.1.jar -7f93a3acf000-7f93a3ad4000 r--s 00048000 fc:01 790179 /opt/installs/gradle-2.1/lib/dom4j-1.6.1.jar -7f93a3ad4000-7f93a3adf000 r--s 00059000 fc:01 790193 /opt/installs/gradle-2.1/lib/gradle-ui-2.1.jar -7f93a3adf000-7f93a3ae1000 r--s 00006000 fc:01 790191 /opt/installs/gradle-2.1/lib/gradle-resources-2.1.jar -7f93a3ae1000-7f93a3ae3000 r--s 00007000 fc:01 790219 /opt/installs/gradle-2.1/lib/objenesis-1.2.jar -7f93a3ae3000-7f93a3ae5000 r--s 00000000 fc:01 790209 /opt/installs/gradle-2.1/lib/minlog-1.2.jar -7f93a3ae5000-7f93a3ae7000 r--s 0000f000 fc:01 790220 /opt/installs/gradle-2.1/lib/reflectasm-1.07-shaded.jar -7f93a3ae7000-7f93a3aeb000 r--s 00026000 fc:01 790205 /opt/installs/gradle-2.1/lib/kryo-2.20.jar -7f93a3aeb000-7f93a3aec000 r--s 00003000 fc:01 790211 /opt/installs/gradle-2.1/lib/native-platform-freebsd-amd64-0.10.jar -7f93a3aec000-7f93a3aed000 r--s 00003000 fc:01 790212 /opt/installs/gradle-2.1/lib/native-platform-freebsd-i386-0.10.jar -7f93a3aed000-7f93a3aee000 r--s 00005000 fc:01 790218 /opt/installs/gradle-2.1/lib/native-platform-windows-i386-0.10.jar -7f93a3aee000-7f93a3aef000 r--s 00005000 fc:01 790217 /opt/installs/gradle-2.1/lib/native-platform-windows-amd64-0.10.jar -7f93a3aef000-7f93a3af0000 r--s 00003000 fc:01 790214 /opt/installs/gradle-2.1/lib/native-platform-linux-i386-0.10.jar -7f93a3af0000-7f93a3af1000 r--s 00003000 fc:01 790213 /opt/installs/gradle-2.1/lib/native-platform-linux-amd64-0.10.jar -7f93a3af1000-7f93a3af2000 r--s 00002000 fc:01 790215 /opt/installs/gradle-2.1/lib/native-platform-osx-amd64-0.10.jar -7f93a3af2000-7f93a3af3000 r--s 00002000 fc:01 790216 /opt/installs/gradle-2.1/lib/native-platform-osx-i386-0.10.jar -7f93a3af3000-7f93a3af5000 r--s 00008000 fc:01 790197 /opt/installs/gradle-2.1/lib/jansi-1.2.1.jar -7f93a3af5000-7f93a3af8000 r--s 0000d000 fc:01 790210 /opt/installs/gradle-2.1/lib/native-platform-0.10.jar -7f93a3af8000-7f93a3afc000 r--s 000e4000 fc:01 790203 /opt/installs/gradle-2.1/lib/jna-3.2.7.jar -7f93a3afc000-7f93a3afd000 r--s 00001000 fc:01 790181 /opt/installs/gradle-2.1/lib/gradle-base-services-groovy-2.1.jar -7f93a3afd000-7f93a3aff000 r--s 00000000 fc:01 790188 /opt/installs/gradle-2.1/lib/gradle-model-groovy-2.1.jar -7f93a3aff000-7f93a3b02000 r--s 00011000 fc:01 790187 /opt/installs/gradle-2.1/lib/gradle-model-core-2.1.jar -7f93a3b02000-7f93a3b03000 r--s 00000000 fc:01 790184 /opt/installs/gradle-2.1/lib/gradle-docs-2.1.jar -7f93a3b03000-7f93a3b05000 r--s 00003000 fc:01 790202 /opt/installs/gradle-2.1/lib/jcl-over-slf4j-1.7.5.jar -7f93a3b05000-7f93a3b07000 r--s 00004000 fc:01 790206 /opt/installs/gradle-2.1/lib/log4j-over-slf4j-1.7.5.jar -7f93a3b07000-7f93a3b0a000 r--s 0001b000 fc:01 790198 /opt/installs/gradle-2.1/lib/jarjar-1.3.jar -7f93a3b0a000-7f93a3b0b000 r--s 00000000 fc:01 790201 /opt/installs/gradle-2.1/lib/jcip-annotations-1.0.jar -7f93a3b0b000-7f93a3b19000 r--s 0007f000 fc:01 790176 /opt/installs/gradle-2.1/lib/commons-collections-3.2.1.jar -7f93a3b19000-7f93a3b20000 r--s 0003a000 fc:01 790185 /opt/installs/gradle-2.1/lib/gradle-launcher-2.1.jar -7f93a3b20000-7f93a3b23000 r--s 0000f000 fc:01 1051802 /opt/installs/gradle-2.1/lib/plugins/gradle-plugin-use-2.1.jar -7f93a3b23000-7f93a3b24000 r--s 00001000 fc:01 1051801 /opt/installs/gradle-2.1/lib/plugins/gradle-plugin-development-2.1.jar -7f93a3b24000-7f93a3b28000 r--s 0000b000 fc:01 1051797 /opt/installs/gradle-2.1/lib/plugins/gradle-language-base-2.1.jar -7f93a3b28000-7f93a3b31000 r--s 0003d000 fc:01 1051798 /opt/installs/gradle-2.1/lib/plugins/gradle-language-jvm-2.1.jar -7f93a3b31000-7f93a3b36000 r--s 00026000 fc:01 1051786 /opt/installs/gradle-2.1/lib/plugins/gradle-build-init-2.1.jar -7f93a3b36000-7f93a3b39000 r--s 0001d000 fc:01 1051794 /opt/installs/gradle-2.1/lib/plugins/gradle-jacoco-2.1.jar -7f93a3b39000-7f93a3b3c000 r--s 0000d000 fc:01 1051793 /opt/installs/gradle-2.1/lib/plugins/gradle-ivy-2.1.jar -7f93a3b3c000-7f93a3b3e000 r--s 00002000 fc:01 1051804 /opt/installs/gradle-2.1/lib/plugins/gradle-publish-2.1.jar -7f93a3b3e000-7f93a3b40000 r--s 00005000 fc:01 1051840 /opt/installs/gradle-2.1/lib/plugins/jatl-0.2.2.jar -7f93a3b40000-7f93a3b42000 r--s 0000f000 fc:01 1051805 /opt/installs/gradle-2.1/lib/plugins/gradle-reporting-2.1.jar -7f93a3b42000-7f93a3b47000 r--s 00038000 fc:01 1051790 /opt/installs/gradle-2.1/lib/plugins/gradle-diagnostics-2.1.jar -7f93a3b47000-7f93a3b4e000 r--s 00090000 fc:01 1051785 /opt/installs/gradle-2.1/lib/plugins/gradle-build-comparison-2.1.jar -7f93a3b4e000-7f93a3b55000 r--s 00035000 fc:01 1051859 /opt/installs/gradle-2.1/lib/plugins/simple-4.1.21.jar -7f93a3b55000-7f93a3b5a000 r--s 0002a000 fc:01 1051810 /opt/installs/gradle-2.1/lib/plugins/gson-2.2.4.jar -7f93a3b5a000-7f93a3b66000 r--s 00100000 fc:01 1051857 /opt/installs/gradle-2.1/lib/plugins/rhino-1.7R3.jar -7f93a3b66000-7f93a3b6a000 r--s 0001f000 fc:01 1051795 /opt/installs/gradle-2.1/lib/plugins/gradle-javascript-2.1.jar -7f93a3b6a000-7f93a3b6c000 r--s 0000e000 fc:01 1051791 /opt/installs/gradle-2.1/lib/plugins/gradle-ear-2.1.jar -7f93a3b6c000-7f93a3b7f000 r--s 000a4000 fc:01 1051789 /opt/installs/gradle-2.1/lib/plugins/gradle-cpp-2.1.jar -7f93a3b7f000-7f93a3ba7000 r--s 00194000 fc:01 1051776 /opt/installs/gradle-2.1/lib/plugins/bcprov-jdk15-1.46.jar -7f93a3ba7000-7f93a3bab000 r--s 00025000 fc:01 1051775 /opt/installs/gradle-2.1/lib/plugins/bcpg-jdk15-1.46.jar -7f93a3bab000-7f93a3bae000 r--s 0001d000 fc:01 1051808 /opt/installs/gradle-2.1/lib/plugins/gradle-signing-2.1.jar -7f93a3bae000-7f93a3baf000 r--s 00002000 fc:01 1051861 /opt/installs/gradle-2.1/lib/plugins/sonar-batch-bootstrapper-2.9.jar -7f93a3baf000-7f93a3bb0000 r--s 00007000 fc:01 1051862 /opt/installs/gradle-2.1/lib/plugins/sonar-runner-2.0.jar -7f93a3bb0000-7f93a3bb3000 r--s 0001e000 fc:01 1051809 /opt/installs/gradle-2.1/lib/plugins/gradle-sonar-2.1.jar -7f93a3bb3000-7f93a3bb6000 r--s 00017000 fc:01 1051807 /opt/installs/gradle-2.1/lib/plugins/gradle-scala-2.1.jar -7f93a3bb6000-7f93a3bb8000 r--s 0000e000 fc:01 1051783 /opt/installs/gradle-2.1/lib/plugins/gradle-announce-2.1.jar -7f93a3bb8000-7f93a3bb9000 r--s 00000000 fc:01 790199 /opt/installs/gradle-2.1/lib/javax.inject-1.jar -7f93a3bb9000-7f93a3bc6000 r--s 000bb000 fc:01 1051792 /opt/installs/gradle-2.1/lib/plugins/gradle-ide-2.1.jar -7f93a3bc6000-7f93a3bc8000 r--s 00000000 fc:01 1051854 /opt/installs/gradle-2.1/lib/plugins/plexus-component-annotations-1.5.2.jar -7f93a3bc8000-7f93a3bcb000 r--s 0000c000 fc:01 1051856 /opt/installs/gradle-2.1/lib/plugins/pmaven-groovy-0.8-20100325.jar -7f93a3bcb000-7f93a3bcc000 r--s 00004000 fc:01 1051855 /opt/installs/gradle-2.1/lib/plugins/pmaven-common-0.8-20100325.jar -7f93a3bcc000-7f93a3be5000 r--s 00129000 fc:01 1051852 /opt/installs/gradle-2.1/lib/plugins/maven-ant-tasks-2.1.3.jar -7f93a3be5000-7f93a3bea000 r--s 0001d000 fc:01 1051799 /opt/installs/gradle-2.1/lib/plugins/gradle-maven-2.1.jar -7f93a3bea000-7f93a3c02000 r--s 0013b000 fc:01 1051777 /opt/installs/gradle-2.1/lib/plugins/bndlib-2.1.0.jar -7f93a3c02000-7f93a3c04000 r--s 00004000 fc:01 1051800 /opt/installs/gradle-2.1/lib/plugins/gradle-osgi-2.1.jar -7f93a3c04000-7f93a3c05000 r--s 00005000 fc:01 790194 /opt/installs/gradle-2.1/lib/gradle-wrapper-2.1.jar -7f93a3c05000-7f93a3c0a000 r--s 00068000 fc:01 1051774 /opt/installs/gradle-2.1/lib/plugins/antlr-2.7.7.jar -7f93a3c0a000-7f93a3c0b000 r--s 00002000 fc:01 1051773 /opt/installs/gradle-2.1/lib/plugins/ant-antlr-1.9.3.jar -7f93a3c0b000-7f93a3c0d000 r--s 00004000 fc:01 1051784 /opt/installs/gradle-2.1/lib/plugins/gradle-antlr-2.1.jar -7f93a3c0d000-7f93a3c10000 r--s 0001e000 fc:01 1051850 /opt/installs/gradle-2.1/lib/plugins/jsp-api-2.1-6.1.14.jar -7f93a3c10000-7f93a3c33000 r--s 00344000 fc:01 1051781 /opt/installs/gradle-2.1/lib/plugins/core-3.1.1.jar -7f93a3c33000-7f93a3c34000 r--s 00006000 fc:01 1051845 /opt/installs/gradle-2.1/lib/plugins/jetty-naming-6.1.25.jar -7f93a3c34000-7f93a3c36000 r--s 00002000 fc:01 1051844 /opt/installs/gradle-2.1/lib/plugins/jetty-annotations-6.1.25.jar -7f93a3c36000-7f93a3c47000 r--s 000ea000 fc:01 1051849 /opt/installs/gradle-2.1/lib/plugins/jsp-2.1-6.1.14.jar -7f93a3c47000-7f93a3c49000 r--s 0000d000 fc:01 1051846 /opt/installs/gradle-2.1/lib/plugins/jetty-plus-6.1.25.jar -7f93a3c49000-7f93a3c4b000 r--s 0001f000 fc:01 1051858 /opt/installs/gradle-2.1/lib/plugins/servlet-api-2.5-20081211.jar -7f93a3c4b000-7f93a3c4f000 r--s 00028000 fc:01 1051847 /opt/installs/gradle-2.1/lib/plugins/jetty-util-6.1.25.jar -7f93a3c4f000-7f93a3c56000 r--s 0007d000 fc:01 1051843 /opt/installs/gradle-2.1/lib/plugins/jetty-6.1.25.jar -7f93a3c56000-7f93a3c58000 r--s 00009000 fc:01 1051796 /opt/installs/gradle-2.1/lib/plugins/gradle-jetty-2.1.jar -7f93a3c58000-7f93a3c5e000 r--s 0003f000 fc:01 1051787 /opt/installs/gradle-2.1/lib/plugins/gradle-code-quality-2.1.jar -7f93a3c5e000-7f93a3c64000 r--s 00033000 fc:01 1051860 /opt/installs/gradle-2.1/lib/plugins/snakeyaml-1.6.jar -7f93a3c64000-7f93a3c69000 r--s 00040000 fc:01 1051778 /opt/installs/gradle-2.1/lib/plugins/bsh-2.0b4.jar -7f93a3c69000-7f93a3c72000 r--s 00089000 fc:01 1051863 /opt/installs/gradle-2.1/lib/plugins/testng-6.3.1.jar -7f93a3c72000-7f93a3c78000 r--s 00036000 fc:01 1051851 /opt/installs/gradle-2.1/lib/plugins/junit-4.11.jar -7f93a3c78000-7f93a3c7d000 r--s 00041000 fc:01 790178 /opt/installs/gradle-2.1/lib/commons-lang-2.6.jar -7f93a3c7d000-7f93a3c82000 r--s 00036000 fc:01 790175 /opt/installs/gradle-2.1/lib/asm-all-5.0.3.jar -7f93a3c82000-7f93a3ced000 r--s 00685000 fc:01 790195 /opt/installs/gradle-2.1/lib/groovy-all-2.3.6.jar -7f93a3ced000-7f93a3cfd000 r-xp 00000000 fc:01 23730618 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libnio.so -7f93a3cfd000-7f93a3efd000 ---p 00010000 fc:01 23730618 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libnio.so -7f93a3efd000-7f93a3efe000 r--p 00010000 fc:01 23730618 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libnio.so -7f93a3efe000-7f93a3eff000 rw-p 00011000 fc:01 23730618 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libnio.so -7f93a3eff000-7f93a3f00000 ---p 00000000 00:00 0 -7f93a3f00000-7f93a4000000 rw-p 00000000 00:00 0 [stack:8603] -7f93a4000000-7f93a4021000 rw-p 00000000 00:00 0 -7f93a4021000-7f93a8000000 ---p 00000000 00:00 0 -7f93a8000000-7f93a8002000 r--s 00009000 fc:01 1051811 /opt/installs/gradle-2.1/lib/plugins/hamcrest-core-1.3.jar -7f93a8002000-7f93a8004000 r--s 00006000 fc:01 1051842 /opt/installs/gradle-2.1/lib/plugins/jcommander-1.12.jar -7f93a8004000-7f93a8023000 r--s 001cc000 fc:01 790173 /opt/installs/gradle-2.1/lib/ant-1.9.3.jar -7f93a8023000-7f93a804b000 r--s 001cf000 fc:01 790196 /opt/installs/gradle-2.1/lib/guava-jdk5-17.0.jar -7f93a804b000-7f93a807c000 r--s 0018f000 fc:01 790183 /opt/installs/gradle-2.1/lib/gradle-core-2.1.jar -7f93a807c000-7f93a807f000 ---p 00000000 00:00 0 -7f93a807f000-7f93a817d000 rw-p 00000000 00:00 0 [stack:8602] -7f93a817d000-7f93a8180000 ---p 00000000 00:00 0 -7f93a8180000-7f93a827e000 rw-p 00000000 00:00 0 [stack:8601] -7f93a827e000-7f93a8281000 ---p 00000000 00:00 0 -7f93a8281000-7f93a837f000 rw-p 00000000 00:00 0 [stack:8600] -7f93a837f000-7f93a8382000 ---p 00000000 00:00 0 -7f93a8382000-7f93a84b1000 rw-p 00000000 00:00 0 [stack:8599] -7f93a84b1000-7f93a84ee000 r-xp 00000000 fc:01 1310890 /lib/x86_64-linux-gnu/libpcre.so.3.13.1 -7f93a84ee000-7f93a86ed000 ---p 0003d000 fc:01 1310890 /lib/x86_64-linux-gnu/libpcre.so.3.13.1 -7f93a86ed000-7f93a86ee000 r--p 0003c000 fc:01 1310890 /lib/x86_64-linux-gnu/libpcre.so.3.13.1 -7f93a86ee000-7f93a86ef000 rw-p 0003d000 fc:01 1310890 /lib/x86_64-linux-gnu/libpcre.so.3.13.1 -7f93a86ef000-7f93a86f6000 r-xp 00000000 fc:01 23732001 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.1 -7f93a86f6000-7f93a88f5000 ---p 00007000 fc:01 23732001 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.1 -7f93a88f5000-7f93a88f6000 r--p 00006000 fc:01 23732001 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.1 -7f93a88f6000-7f93a88f7000 rw-p 00007000 fc:01 23732001 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.1 -7f93a88f7000-7f93a890e000 r-xp 00000000 fc:01 1316447 /lib/x86_64-linux-gnu/libresolv-2.19.so -7f93a890e000-7f93a8b0e000 ---p 00017000 fc:01 1316447 /lib/x86_64-linux-gnu/libresolv-2.19.so -7f93a8b0e000-7f93a8b0f000 r--p 00017000 fc:01 1316447 /lib/x86_64-linux-gnu/libresolv-2.19.so -7f93a8b0f000-7f93a8b10000 rw-p 00018000 fc:01 1316447 /lib/x86_64-linux-gnu/libresolv-2.19.so -7f93a8b10000-7f93a8b12000 rw-p 00000000 00:00 0 -7f93a8b12000-7f93a8b32000 r-xp 00000000 fc:01 1314864 /lib/x86_64-linux-gnu/libselinux.so.1 -7f93a8b32000-7f93a8d31000 ---p 00020000 fc:01 1314864 /lib/x86_64-linux-gnu/libselinux.so.1 -7f93a8d31000-7f93a8d32000 r--p 0001f000 fc:01 1314864 /lib/x86_64-linux-gnu/libselinux.so.1 -7f93a8d32000-7f93a8d33000 rw-p 00020000 fc:01 1314864 /lib/x86_64-linux-gnu/libselinux.so.1 -7f93a8d33000-7f93a8d35000 rw-p 00000000 00:00 0 -7f93a8d35000-7f93a8d38000 r-xp 00000000 fc:01 23732114 /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0.4002.0 -7f93a8d38000-7f93a8f37000 ---p 00003000 fc:01 23732114 /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0.4002.0 -7f93a8f37000-7f93a8f38000 r--p 00002000 fc:01 23732114 /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0.4002.0 -7f93a8f38000-7f93a8f39000 rw-p 00003000 fc:01 23732114 /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0.4002.0 -7f93a8f39000-7f93a903f000 r-xp 00000000 fc:01 1314765 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0 -7f93a903f000-7f93a923e000 ---p 00106000 fc:01 1314765 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0 -7f93a923e000-7f93a923f000 r--p 00105000 fc:01 1314765 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0 -7f93a923f000-7f93a9240000 rw-p 00106000 fc:01 1314765 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0 -7f93a9240000-7f93a9241000 rw-p 00000000 00:00 0 -7f93a9241000-7f93a9290000 r-xp 00000000 fc:01 23732130 /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4002.0 -7f93a9290000-7f93a9490000 ---p 0004f000 fc:01 23732130 /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4002.0 -7f93a9490000-7f93a9491000 r--p 0004f000 fc:01 23732130 /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4002.0 -7f93a9491000-7f93a9492000 rw-p 00050000 fc:01 23732130 /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4002.0 -7f93a9492000-7f93a95fe000 r-xp 00000000 fc:01 23732102 /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.4002.0 -7f93a95fe000-7f93a97fd000 ---p 0016c000 fc:01 23732102 /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.4002.0 -7f93a97fd000-7f93a9801000 r--p 0016b000 fc:01 23732102 /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.4002.0 -7f93a9801000-7f93a9803000 rw-p 0016f000 fc:01 23732102 /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.4002.0 -7f93a9803000-7f93a9805000 rw-p 00000000 00:00 0 -7f93a9805000-7f93a9806000 r--s 00002000 fc:01 1051782 /opt/installs/gradle-2.1/lib/plugins/geronimo-annotation_1.0_spec-1.0.jar -7f93a9806000-7f93a9812000 r--s 00075000 fc:01 1051803 /opt/installs/gradle-2.1/lib/plugins/gradle-plugins-2.1.jar -7f93a9812000-7f93a981c000 r--s 0005d000 fc:01 790208 /opt/installs/gradle-2.1/lib/logback-core-1.0.13.jar -7f93a981c000-7f93a9822000 r--s 0003b000 fc:01 790207 /opt/installs/gradle-2.1/lib/logback-classic-1.0.13.jar -7f93a9822000-7f93a9839000 r-xp 00000000 fc:01 23730649 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libnet.so -7f93a9839000-7f93a9a38000 ---p 00017000 fc:01 23730649 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libnet.so -7f93a9a38000-7f93a9a39000 r--p 00016000 fc:01 23730649 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libnet.so -7f93a9a39000-7f93a9a3a000 rw-p 00017000 fc:01 23730649 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libnet.so -7f93a9a3a000-7f93aa11c000 r--p 00000000 fc:01 23730739 /usr/lib/locale/locale-archive -7f93aa11c000-7f93aa11f000 ---p 00000000 00:00 0 -7f93aa11f000-7f93aa21d000 rw-p 00000000 00:00 0 [stack:8594] -7f93aa21d000-7f93aa220000 ---p 00000000 00:00 0 -7f93aa220000-7f93aa31e000 rw-p 00000000 00:00 0 [stack:8593] -7f93aa31e000-7f93aa31f000 ---p 00000000 00:00 0 -7f93aa31f000-7f93ac000000 rw-p 00000000 00:00 0 [stack:8592] -7f93ac000000-7f93ac021000 rw-p 00000000 00:00 0 -7f93ac021000-7f93b0000000 ---p 00000000 00:00 0 -7f93b0000000-7f93b0002000 r--s 00009000 fc:01 1051779 /opt/installs/gradle-2.1/lib/plugins/commons-cli-1.2.jar -7f93b0002000-7f93b000a000 r--s 00039000 fc:01 790186 /opt/installs/gradle-2.1/lib/gradle-messaging-2.1.jar -7f93b000a000-7f93b00b6000 rw-p 00000000 00:00 0 -7f93b00b6000-7f93b0268000 r--s 01d30000 fc:01 23730047 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar -7f93b0268000-7f93b0afb000 rw-p 00000000 00:00 0 -7f93b0afb000-7f93b0afc000 ---p 00000000 00:00 0 -7f93b0afc000-7f93b0bfc000 rw-p 00000000 00:00 0 [stack:8591] -7f93b0bfc000-7f93b0bfd000 ---p 00000000 00:00 0 -7f93b0bfd000-7f93b0cfd000 rw-p 00000000 00:00 0 [stack:8590] -7f93b0cfd000-7f93b0cfe000 ---p 00000000 00:00 0 -7f93b0cfe000-7f93b0dfe000 rw-p 00000000 00:00 0 [stack:8589] -7f93b0dfe000-7f93b0dff000 ---p 00000000 00:00 0 -7f93b0dff000-7f93b0eff000 rw-p 00000000 00:00 0 [stack:8588] -7f93b0eff000-7f93b0f00000 ---p 00000000 00:00 0 -7f93b0f00000-7f93b1000000 rw-p 00000000 00:00 0 [stack:8587] -7f93b1000000-7f93b1270000 rwxp 00000000 00:00 0 -7f93b1270000-7f93b4a39000 rw-p 00000000 00:00 0 -7f93b4a39000-7f93b8000000 ---p 00000000 00:00 0 -7f93b8000000-7f93b80d5000 rw-p 00000000 00:00 0 -7f93b80d5000-7f93b80d6000 ---p 00000000 00:00 0 -7f93b80d6000-7f93b81d6000 rw-p 00000000 00:00 0 [stack:8586] -7f93b81d6000-7f93b81d7000 ---p 00000000 00:00 0 -7f93b81d7000-7f93b82d7000 rw-p 00000000 00:00 0 [stack:8585] -7f93b82d7000-7f93b82d8000 ---p 00000000 00:00 0 -7f93b82d8000-7f93b83e3000 rw-p 00000000 00:00 0 [stack:8584] -7f93b83e3000-7f93b842b000 rw-p 00000000 00:00 0 -7f93b842b000-7f93b847e000 rw-p 00000000 00:00 0 -7f93b847e000-7f93b895d000 rw-p 00000000 00:00 0 -7f93b895d000-7f93b8968000 rw-p 00000000 00:00 0 -7f93b8968000-7f93b89b0000 rw-p 00000000 00:00 0 -7f93b89b0000-7f93b8a03000 rw-p 00000000 00:00 0 -7f93b8a03000-7f93b8ee1000 rw-p 00000000 00:00 0 -7f93b8ee1000-7f93b8fe5000 rw-p 00000000 00:00 0 -7f93b8fe5000-7f93b917a000 rw-p 00000000 00:00 0 -7f93b917a000-7f93b917b000 rw-p 00000000 00:00 0 -7f93b917b000-7f93b9183000 r-xp 00000000 fc:01 23730623 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libzip.so -7f93b9183000-7f93b9382000 ---p 00008000 fc:01 23730623 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libzip.so -7f93b9382000-7f93b9383000 r--p 00007000 fc:01 23730623 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libzip.so -7f93b9383000-7f93b9384000 rw-p 00008000 fc:01 23730623 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libzip.so -7f93b9384000-7f93b938f000 r-xp 00000000 fc:01 1316449 /lib/x86_64-linux-gnu/libnss_files-2.19.so -7f93b938f000-7f93b958e000 ---p 0000b000 fc:01 1316449 /lib/x86_64-linux-gnu/libnss_files-2.19.so -7f93b958e000-7f93b958f000 r--p 0000a000 fc:01 1316449 /lib/x86_64-linux-gnu/libnss_files-2.19.so -7f93b958f000-7f93b9590000 rw-p 0000b000 fc:01 1316449 /lib/x86_64-linux-gnu/libnss_files-2.19.so -7f93b9590000-7f93b959b000 r-xp 00000000 fc:01 1316469 /lib/x86_64-linux-gnu/libnss_nis-2.19.so -7f93b959b000-7f93b979a000 ---p 0000b000 fc:01 1316469 /lib/x86_64-linux-gnu/libnss_nis-2.19.so -7f93b979a000-7f93b979b000 r--p 0000a000 fc:01 1316469 /lib/x86_64-linux-gnu/libnss_nis-2.19.so -7f93b979b000-7f93b979c000 rw-p 0000b000 fc:01 1316469 /lib/x86_64-linux-gnu/libnss_nis-2.19.so -7f93b979c000-7f93b97b3000 r-xp 00000000 fc:01 1316458 /lib/x86_64-linux-gnu/libnsl-2.19.so -7f93b97b3000-7f93b99b2000 ---p 00017000 fc:01 1316458 /lib/x86_64-linux-gnu/libnsl-2.19.so -7f93b99b2000-7f93b99b3000 r--p 00016000 fc:01 1316458 /lib/x86_64-linux-gnu/libnsl-2.19.so -7f93b99b3000-7f93b99b4000 rw-p 00017000 fc:01 1316458 /lib/x86_64-linux-gnu/libnsl-2.19.so -7f93b99b4000-7f93b99b6000 rw-p 00000000 00:00 0 -7f93b99b6000-7f93b99bf000 r-xp 00000000 fc:01 1316457 /lib/x86_64-linux-gnu/libnss_compat-2.19.so -7f93b99bf000-7f93b9bbe000 ---p 00009000 fc:01 1316457 /lib/x86_64-linux-gnu/libnss_compat-2.19.so -7f93b9bbe000-7f93b9bbf000 r--p 00008000 fc:01 1316457 /lib/x86_64-linux-gnu/libnss_compat-2.19.so -7f93b9bbf000-7f93b9bc0000 rw-p 00009000 fc:01 1316457 /lib/x86_64-linux-gnu/libnss_compat-2.19.so -7f93b9bc0000-7f93b9beb000 r-xp 00000000 fc:01 23730631 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libjava.so -7f93b9beb000-7f93b9deb000 ---p 0002b000 fc:01 23730631 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libjava.so -7f93b9deb000-7f93b9dec000 r--p 0002b000 fc:01 23730631 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libjava.so -7f93b9dec000-7f93b9dee000 rw-p 0002c000 fc:01 23730631 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libjava.so -7f93b9dee000-7f93b9dfe000 r-xp 00000000 fc:01 23730645 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libverify.so -7f93b9dfe000-7f93b9ffd000 ---p 00010000 fc:01 23730645 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libverify.so -7f93b9ffd000-7f93b9fff000 r--p 0000f000 fc:01 23730645 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libverify.so -7f93b9fff000-7f93ba000000 rw-p 00011000 fc:01 23730645 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/libverify.so -7f93ba000000-7f93ba007000 r-xp 00000000 fc:01 1316466 /lib/x86_64-linux-gnu/librt-2.19.so -7f93ba007000-7f93ba206000 ---p 00007000 fc:01 1316466 /lib/x86_64-linux-gnu/librt-2.19.so -7f93ba206000-7f93ba207000 r--p 00006000 fc:01 1316466 /lib/x86_64-linux-gnu/librt-2.19.so -7f93ba207000-7f93ba208000 rw-p 00007000 fc:01 1316466 /lib/x86_64-linux-gnu/librt-2.19.so -7f93ba208000-7f93ba21e000 r-xp 00000000 fc:01 1314761 /lib/x86_64-linux-gnu/libgcc_s.so.1 -7f93ba21e000-7f93ba41d000 ---p 00016000 fc:01 1314761 /lib/x86_64-linux-gnu/libgcc_s.so.1 -7f93ba41d000-7f93ba41e000 rw-p 00015000 fc:01 1314761 /lib/x86_64-linux-gnu/libgcc_s.so.1 -7f93ba41e000-7f93ba523000 r-xp 00000000 fc:01 1316448 /lib/x86_64-linux-gnu/libm-2.19.so -7f93ba523000-7f93ba722000 ---p 00105000 fc:01 1316448 /lib/x86_64-linux-gnu/libm-2.19.so -7f93ba722000-7f93ba723000 r--p 00104000 fc:01 1316448 /lib/x86_64-linux-gnu/libm-2.19.so -7f93ba723000-7f93ba724000 rw-p 00105000 fc:01 1316448 /lib/x86_64-linux-gnu/libm-2.19.so -7f93ba724000-7f93ba80a000 r-xp 00000000 fc:01 23728291 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19 -7f93ba80a000-7f93baa09000 ---p 000e6000 fc:01 23728291 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19 -7f93baa09000-7f93baa11000 r--p 000e5000 fc:01 23728291 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19 -7f93baa11000-7f93baa13000 rw-p 000ed000 fc:01 23728291 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19 -7f93baa13000-7f93baa28000 rw-p 00000000 00:00 0 -7f93baa28000-7f93bb54c000 r-xp 00000000 fc:01 23730637 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server/libjvm.so -7f93bb54c000-7f93bb74b000 ---p 00b24000 fc:01 23730637 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server/libjvm.so -7f93bb74b000-7f93bb7e5000 r--p 00b23000 fc:01 23730637 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server/libjvm.so -7f93bb7e5000-7f93bb808000 rw-p 00bbd000 fc:01 23730637 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server/libjvm.so -7f93bb808000-7f93bb836000 rw-p 00000000 00:00 0 -7f93bb836000-7f93bb84e000 r-xp 00000000 fc:01 1314897 /lib/x86_64-linux-gnu/libz.so.1.2.8 -7f93bb84e000-7f93bba4d000 ---p 00018000 fc:01 1314897 /lib/x86_64-linux-gnu/libz.so.1.2.8 -7f93bba4d000-7f93bba4e000 r--p 00017000 fc:01 1314897 /lib/x86_64-linux-gnu/libz.so.1.2.8 -7f93bba4e000-7f93bba4f000 rw-p 00018000 fc:01 1314897 /lib/x86_64-linux-gnu/libz.so.1.2.8 -7f93bba4f000-7f93bba68000 r-xp 00000000 fc:01 1316464 /lib/x86_64-linux-gnu/libpthread-2.19.so -7f93bba68000-7f93bbc67000 ---p 00019000 fc:01 1316464 /lib/x86_64-linux-gnu/libpthread-2.19.so -7f93bbc67000-7f93bbc68000 r--p 00018000 fc:01 1316464 /lib/x86_64-linux-gnu/libpthread-2.19.so -7f93bbc68000-7f93bbc69000 rw-p 00019000 fc:01 1316464 /lib/x86_64-linux-gnu/libpthread-2.19.so -7f93bbc69000-7f93bbc6d000 rw-p 00000000 00:00 0 -7f93bbc6d000-7f93bbc70000 r-xp 00000000 fc:01 1316452 /lib/x86_64-linux-gnu/libdl-2.19.so -7f93bbc70000-7f93bbe6f000 ---p 00003000 fc:01 1316452 /lib/x86_64-linux-gnu/libdl-2.19.so -7f93bbe6f000-7f93bbe70000 r--p 00002000 fc:01 1316452 /lib/x86_64-linux-gnu/libdl-2.19.so -7f93bbe70000-7f93bbe71000 rw-p 00003000 fc:01 1316452 /lib/x86_64-linux-gnu/libdl-2.19.so -7f93bbe71000-7f93bc02c000 r-xp 00000000 fc:01 1316463 /lib/x86_64-linux-gnu/libc-2.19.so -7f93bc02c000-7f93bc22b000 ---p 001bb000 fc:01 1316463 /lib/x86_64-linux-gnu/libc-2.19.so -7f93bc22b000-7f93bc22f000 r--p 001ba000 fc:01 1316463 /lib/x86_64-linux-gnu/libc-2.19.so -7f93bc22f000-7f93bc231000 rw-p 001be000 fc:01 1316463 /lib/x86_64-linux-gnu/libc-2.19.so -7f93bc231000-7f93bc236000 rw-p 00000000 00:00 0 -7f93bc236000-7f93bc243000 r-xp 00000000 fc:01 23730646 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/jli/libjli.so -7f93bc243000-7f93bc442000 ---p 0000d000 fc:01 23730646 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/jli/libjli.so -7f93bc442000-7f93bc443000 r--p 0000c000 fc:01 23730646 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/jli/libjli.so -7f93bc443000-7f93bc444000 rw-p 0000d000 fc:01 23730646 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/jli/libjli.so -7f93bc444000-7f93bc467000 r-xp 00000000 fc:01 1316460 /lib/x86_64-linux-gnu/ld-2.19.so -7f93bc467000-7f93bc468000 r--s 00004000 fc:01 790174 /opt/installs/gradle-2.1/lib/ant-launcher-1.9.3.jar -7f93bc468000-7f93bc46b000 r--s 00018000 fc:01 790177 /opt/installs/gradle-2.1/lib/commons-io-1.4.jar -7f93bc46b000-7f93bc46c000 r--s 00001000 fc:01 790204 /opt/installs/gradle-2.1/lib/jul-to-slf4j-1.7.5.jar -7f93bc46c000-7f93bc46e000 r--s 00005000 fc:01 790221 /opt/installs/gradle-2.1/lib/slf4j-api-1.7.5.jar -7f93bc46e000-7f93bc471000 r--s 00007000 fc:01 790189 /opt/installs/gradle-2.1/lib/gradle-native-2.1.jar -7f93bc471000-7f93bc473000 r--s 00005000 fc:01 790182 /opt/installs/gradle-2.1/lib/gradle-cli-2.1.jar -7f93bc473000-7f93bc479000 r--s 00025000 fc:01 790180 /opt/installs/gradle-2.1/lib/gradle-base-services-2.1.jar -7f93bc479000-7f93bc47e000 r--s 0004e000 fc:01 23730660 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jsse.jar -7f93bc47e000-7f93bc47f000 r--p 00000000 fc:01 25437279 /usr/share/locale-langpack/en_AU/LC_MESSAGES/libc.mo -7f93bc47f000-7f93bc480000 r--s 00001000 00:1f 22552407 /home/dgh/.gradle/caches/2.1/workerMain/gradle-worker.jar -7f93bc480000-7f93bc481000 r--s 00002000 fc:01 23729945 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/ext/dnsns.jar -7f93bc481000-7f93bc48b000 rw-p 00000000 00:00 0 -7f93bc48b000-7f93bc541000 rw-p 00000000 00:00 0 -7f93bc541000-7f93bc544000 ---p 00000000 00:00 0 -7f93bc544000-7f93bc647000 rw-p 00000000 00:00 0 [stack:8583] -7f93bc647000-7f93bc64b000 r--s 00034000 fc:01 23729943 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/ext/sunjce_provider.jar -7f93bc64b000-7f93bc64d000 r--s 00006000 fc:01 24122929 /usr/share/java/java-atk-wrapper.jar -7f93bc64d000-7f93bc651000 r--s 0003c000 fc:01 23729944 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/ext/sunpkcs11.jar -7f93bc651000-7f93bc654000 r--s 0000f000 fc:01 23729942 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/ext/icedtea-sound.jar -7f93bc654000-7f93bc656000 r--s 00012000 fc:01 23729940 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/ext/zipfs.jar -7f93bc656000-7f93bc65a000 r--s 00085000 fc:01 23729941 /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/ext/localedata.jar -7f93bc65a000-7f93bc662000 rw-s 00000000 fc:01 26479234 /tmp/hsperfdata_dgh/8578 -7f93bc662000-7f93bc663000 rw-p 00000000 00:00 0 -7f93bc663000-7f93bc664000 ---p 00000000 00:00 0 -7f93bc664000-7f93bc666000 rw-p 00000000 00:00 0 -7f93bc666000-7f93bc667000 r--p 00022000 fc:01 1316460 /lib/x86_64-linux-gnu/ld-2.19.so -7f93bc667000-7f93bc668000 rw-p 00023000 fc:01 1316460 /lib/x86_64-linux-gnu/ld-2.19.so -7f93bc668000-7f93bc669000 rw-p 00000000 00:00 0 -7fff9cf0f000-7fff9cf30000 rw-p 00000000 00:00 0 [stack] -7fff9cf90000-7fff9cf92000 r-xp 00000000 00:00 0 [vdso] -7fff9cf92000-7fff9cf94000 r--p 00000000 00:00 0 [vvar] -ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] - -VM Arguments: -jvm_args: -Dbc.test.data.home=/home/dgh/bc/git/repositories/bc-java/core/src/test/data -Djava.security.manager=jarjar.org.gradle.process.internal.child.BootstrapSecurityManager -Dnet.sourceforge.cobertura.datafile=/home/dgh/bc/git/repositories/bc-java/core/build/cobertura/cobertura.ser -Dfile.encoding=UTF-8 -Duser.country=AU -Duser.language=en -Duser.variant -ea -java_command: jarjar.org.gradle.process.internal.launcher.GradleWorkerMain 'Gradle Test Executor 1' -Launcher Type: SUN_STANDARD - -Environment Variables: -JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64 -PATH=/opt/gradle/bin:/usr/lib/jvm/java-7-openjdk-amd64/bin:/home/dgh/bin:/opt/idea/bin:/opt/ant/bin:/home/dgh/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games -SHELL=/bin/bash -DISPLAY=:0 - -Signal Handlers: -SIGSEGV: [libjvm.so+0x954820], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004 -SIGBUS: [libjvm.so+0x954820], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004 -SIGFPE: [libjvm.so+0x7cb150], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004 -SIGPIPE: SIG_IGN, sa_mask[0]=0x00000000, sa_flags=0x00000000 -SIGXFSZ: [libjvm.so+0x7cb150], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004 -SIGILL: [libjvm.so+0x7cb150], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004 -SIGUSR1: SIG_DFL, sa_mask[0]=0x00000000, sa_flags=0x00000000 -SIGUSR2: [libjvm.so+0x7caff0], sa_mask[0]=0x00000004, sa_flags=0x10000004 -SIGHUP: [libjvm.so+0x7cb1d0], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004 -SIGINT: [libjvm.so+0x7cb1d0], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004 -SIGTERM: [libjvm.so+0x7cb1d0], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004 -SIGQUIT: [libjvm.so+0x7cb1d0], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004 -SIGTRAP: SIG_DFL, sa_mask[0]=0x00000000, sa_flags=0x00000000 - - ---------------- S Y S T E M --------------- - -OS:Ubuntu 14.04 (trusty) -uname:Linux 3.16.0-33-generic #44~14.04.1-Ubuntu SMP Fri Mar 13 10:33:29 UTC 2015 x86_64 -libc:glibc 2.19 NPTL 2.19 -rlimit: STACK 8192k, CORE 0k, NPROC 63500, NOFILE 4096, AS infinity -load average:7.11 5.01 4.42 - -/proc/meminfo: -MemTotal: 16334712 kB -MemFree: 168148 kB -MemAvailable: 154084 kB -Buffers: 368 kB -Cached: 1391384 kB -SwapCached: 0 kB -Active: 14383800 kB -Inactive: 1244816 kB -Active(anon): 14375232 kB -Inactive(anon): 1233916 kB -Active(file): 8568 kB -Inactive(file): 10900 kB -Unevictable: 340 kB -Mlocked: 340 kB -SwapTotal: 0 kB -SwapFree: 0 kB -Dirty: 372 kB -Writeback: 0 kB -AnonPages: 14241228 kB -Mapped: 635804 kB -Shmem: 1368788 kB -Slab: 248980 kB -SReclaimable: 121328 kB -SUnreclaim: 127652 kB -KernelStack: 23216 kB -PageTables: 106216 kB -NFS_Unstable: 0 kB -Bounce: 0 kB -WritebackTmp: 0 kB -CommitLimit: 8167356 kB -Committed_AS: 31371576 kB -VmallocTotal: 34359738367 kB -VmallocUsed: 453564 kB -VmallocChunk: 34359174720 kB -HardwareCorrupted: 0 kB -AnonHugePages: 5378048 kB -HugePages_Total: 0 -HugePages_Free: 0 -HugePages_Rsvd: 0 -HugePages_Surp: 0 -Hugepagesize: 2048 kB -DirectMap4k: 169424 kB -DirectMap2M: 10217472 kB -DirectMap1G: 6291456 kB - - -CPU:total 8 (4 cores per cpu, 2 threads per core) family 6 model 60 stepping 3, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3, sse4.1, sse4.2, popcnt, avx, avx2, aes, erms, ht, tsc, tscinvbit - -/proc/cpuinfo: -processor : 0 -vendor_id : GenuineIntel -cpu family : 6 -model : 60 -model name : Intel(R) Core(TM) i7-4712HQ CPU @ 2.30GHz -stepping : 3 -microcode : 0x17 -cpu MHz : 2999.972 -cache size : 6144 KB -physical id : 0 -siblings : 8 -core id : 0 -cpu cores : 4 -apicid : 0 -initial apicid : 0 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid -bogomips : 4589.16 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 1 -vendor_id : GenuineIntel -cpu family : 6 -model : 60 -model name : Intel(R) Core(TM) i7-4712HQ CPU @ 2.30GHz -stepping : 3 -microcode : 0x17 -cpu MHz : 3000.781 -cache size : 6144 KB -physical id : 0 -siblings : 8 -core id : 1 -cpu cores : 4 -apicid : 2 -initial apicid : 2 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid -bogomips : 4589.16 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 2 -vendor_id : GenuineIntel -cpu family : 6 -model : 60 -model name : Intel(R) Core(TM) i7-4712HQ CPU @ 2.30GHz -stepping : 3 -microcode : 0x17 -cpu MHz : 2999.972 -cache size : 6144 KB -physical id : 0 -siblings : 8 -core id : 2 -cpu cores : 4 -apicid : 4 -initial apicid : 4 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid -bogomips : 4589.16 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 3 -vendor_id : GenuineIntel -cpu family : 6 -model : 60 -model name : Intel(R) Core(TM) i7-4712HQ CPU @ 2.30GHz -stepping : 3 -microcode : 0x17 -cpu MHz : 3017.761 -cache size : 6144 KB -physical id : 0 -siblings : 8 -core id : 3 -cpu cores : 4 -apicid : 6 -initial apicid : 6 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid -bogomips : 4589.16 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 4 -vendor_id : GenuineIntel -cpu family : 6 -model : 60 -model name : Intel(R) Core(TM) i7-4712HQ CPU @ 2.30GHz -stepping : 3 -microcode : 0x17 -cpu MHz : 2999.972 -cache size : 6144 KB -physical id : 0 -siblings : 8 -core id : 0 -cpu cores : 4 -apicid : 1 -initial apicid : 1 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid -bogomips : 4589.16 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 5 -vendor_id : GenuineIntel -cpu family : 6 -model : 60 -model name : Intel(R) Core(TM) i7-4712HQ CPU @ 2.30GHz -stepping : 3 -microcode : 0x17 -cpu MHz : 3001.859 -cache size : 6144 KB -physical id : 0 -siblings : 8 -core id : 1 -cpu cores : 4 -apicid : 3 -initial apicid : 3 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid -bogomips : 4589.16 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 6 -vendor_id : GenuineIntel -cpu family : 6 -model : 60 -model name : Intel(R) Core(TM) i7-4712HQ CPU @ 2.30GHz -stepping : 3 -microcode : 0x17 -cpu MHz : 2999.972 -cache size : 6144 KB -physical id : 0 -siblings : 8 -core id : 2 -cpu cores : 4 -apicid : 5 -initial apicid : 5 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid -bogomips : 4589.16 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 7 -vendor_id : GenuineIntel -cpu family : 6 -model : 60 -model name : Intel(R) Core(TM) i7-4712HQ CPU @ 2.30GHz -stepping : 3 -microcode : 0x17 -cpu MHz : 3000.062 -cache size : 6144 KB -physical id : 0 -siblings : 8 -core id : 3 -cpu cores : 4 -apicid : 7 -initial apicid : 7 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid -bogomips : 4589.16 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - - - -Memory: 4k page, physical 16334712k(167652k free), swap 0k(0k free) - -vm_info: OpenJDK 64-Bit Server VM (24.85-b03) for linux-amd64 JRE (1.7.0_85-b01), built on Oct 22 2015 06:46:50 by "buildd" with gcc 4.8.2 - -time: Sun Nov 15 13:49:45 2015 -elapsed time: 18 seconds - diff -Nru bouncycastle-1.55/core/KDFCTR.gen bouncycastle-1.56/core/KDFCTR.gen --- bouncycastle-1.55/core/KDFCTR.gen 2016-05-09 23:40:33.000000000 +0000 +++ bouncycastle-1.56/core/KDFCTR.gen 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - *** *** *** diff -Nru bouncycastle-1.55/core/KDFDblPipelineCounter.gen bouncycastle-1.56/core/KDFDblPipelineCounter.gen --- bouncycastle-1.55/core/KDFDblPipelineCounter.gen 2016-05-09 23:40:33.000000000 +0000 +++ bouncycastle-1.56/core/KDFDblPipelineCounter.gen 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - *** *** *** diff -Nru bouncycastle-1.55/core/KDFDblPipelineNoCounter.gen bouncycastle-1.56/core/KDFDblPipelineNoCounter.gen --- bouncycastle-1.55/core/KDFDblPipelineNoCounter.gen 2016-05-09 23:40:33.000000000 +0000 +++ bouncycastle-1.56/core/KDFDblPipelineNoCounter.gen 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - *** *** *** diff -Nru bouncycastle-1.55/core/KDFFeedbackCounter.gen bouncycastle-1.56/core/KDFFeedbackCounter.gen --- bouncycastle-1.55/core/KDFFeedbackCounter.gen 2016-05-09 23:40:33.000000000 +0000 +++ bouncycastle-1.56/core/KDFFeedbackCounter.gen 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - *** *** *** diff -Nru bouncycastle-1.55/core/KDFFeedbackNoCounter.gen bouncycastle-1.56/core/KDFFeedbackNoCounter.gen --- bouncycastle-1.55/core/KDFFeedbackNoCounter.gen 2016-05-09 23:40:33.000000000 +0000 +++ bouncycastle-1.56/core/KDFFeedbackNoCounter.gen 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - *** *** *** diff -Nru bouncycastle-1.55/core/src/main/j2me/org/bouncycastle/crypto/encodings/PKCS1Encoding.java bouncycastle-1.56/core/src/main/j2me/org/bouncycastle/crypto/encodings/PKCS1Encoding.java --- bouncycastle-1.55/core/src/main/j2me/org/bouncycastle/crypto/encodings/PKCS1Encoding.java 2015-10-08 00:39:11.000000000 +0000 +++ bouncycastle-1.56/core/src/main/j2me/org/bouncycastle/crypto/encodings/PKCS1Encoding.java 2016-12-20 01:53:07.000000000 +0000 @@ -7,6 +7,7 @@ import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.util.Arrays; /** * this does your basic PKCS 1 v1.5 padding - whether or not you should be using this @@ -32,33 +33,35 @@ private static final int HEADER_LENGTH = 10; - private SecureRandom random; - private AsymmetricBlockCipher engine; - private boolean forEncryption; - private boolean forPrivateKey; - private boolean useStrictLength; - private int pLen = -1; - private byte[] fallback = null; + private SecureRandom random; + private AsymmetricBlockCipher engine; + private boolean forEncryption; + private boolean forPrivateKey; + private boolean useStrictLength; + private int pLen = -1; + private byte[] fallback = null; + private byte[] blockBuffer; /** * Basic constructor. + * * @param cipher */ public PKCS1Encoding( - AsymmetricBlockCipher cipher) + AsymmetricBlockCipher cipher) { this.engine = cipher; this.useStrictLength = useStrict(); - } + } /** * Constructor for decryption with a fixed plaintext length. - * + * * @param cipher The cipher to use for cryptographic operation. - * @param pLen Length of the expected plaintext. + * @param pLen Length of the expected plaintext. */ public PKCS1Encoding( - AsymmetricBlockCipher cipher, + AsymmetricBlockCipher cipher, int pLen) { this.engine = cipher; @@ -66,27 +69,24 @@ this.pLen = pLen; } - /** - * Constructor for decryption with a fixed plaintext length and a fallback - * value that is returned, if the padding is incorrect. - * - * @param cipher - * The cipher to use for cryptographic operation. - * @param fallback - * The fallback value, we don't to a arraycopy here. - */ - public PKCS1Encoding( - AsymmetricBlockCipher cipher, + /** + * Constructor for decryption with a fixed plaintext length and a fallback + * value that is returned, if the padding is incorrect. + * + * @param cipher The cipher to use for cryptographic operation. + * @param fallback The fallback value, we don't do an arraycopy here. + */ + public PKCS1Encoding( + AsymmetricBlockCipher cipher, byte[] fallback) { - this.engine = cipher; - this.useStrictLength = useStrict(); - this.fallback = fallback; - this.pLen = fallback.length; + this.engine = cipher; + this.useStrictLength = useStrict(); + this.fallback = fallback; + this.pLen = fallback.length; } - - + // // for J2ME compatibility // @@ -110,33 +110,42 @@ } public void init( - boolean forEncryption, - CipherParameters param) + boolean forEncryption, + CipherParameters param) { - AsymmetricKeyParameter kParam; + AsymmetricKeyParameter kParam; if (param instanceof ParametersWithRandom) { - ParametersWithRandom rParam = (ParametersWithRandom)param; + ParametersWithRandom rParam = (ParametersWithRandom)param; this.random = rParam.getRandom(); kParam = (AsymmetricKeyParameter)rParam.getParameters(); } else { - this.random = new SecureRandom(); kParam = (AsymmetricKeyParameter)param; + if (!kParam.isPrivate() && forEncryption) + { + this.random = new SecureRandom(); + } } engine.init(forEncryption, param); this.forPrivateKey = kParam.isPrivate(); this.forEncryption = forEncryption; + this.blockBuffer = new byte[engine.getOutputBlockSize()]; + + if (pLen > 0 && fallback == null && random == null) + { + throw new IllegalArgumentException("encoder requires random"); + } } public int getInputBlockSize() { - int baseBlockSize = engine.getInputBlockSize(); + int baseBlockSize = engine.getInputBlockSize(); if (forEncryption) { @@ -150,7 +159,7 @@ public int getOutputBlockSize() { - int baseBlockSize = engine.getOutputBlockSize(); + int baseBlockSize = engine.getOutputBlockSize(); if (forEncryption) { @@ -163,9 +172,9 @@ } public byte[] processBlock( - byte[] in, - int inOff, - int inLen) + byte[] in, + int inOff, + int inLen) throws InvalidCipherTextException { if (forEncryption) @@ -179,17 +188,17 @@ } private byte[] encodeBlock( - byte[] in, - int inOff, - int inLen) + byte[] in, + int inOff, + int inLen) throws InvalidCipherTextException { if (inLen > getInputBlockSize()) { throw new IllegalArgumentException("input data too large"); } - - byte[] block = new byte[engine.getInputBlockSize()]; + + byte[] block = new byte[engine.getInputBlockSize()]; if (forPrivateKey) { @@ -224,62 +233,63 @@ return engine.processBlock(block, 0, block.length); } - + /** * Checks if the argument is a correctly PKCS#1.5 encoded Plaintext * for encryption. - * + * * @param encoded The Plaintext. - * @param pLen Expected length of the plaintext. + * @param pLen Expected length of the plaintext. * @return Either 0, if the encoding is correct, or -1, if it is incorrect. */ - private static int checkPkcs1Encoding(byte[] encoded, int pLen) { - int correct = 0; - /* + private static int checkPkcs1Encoding(byte[] encoded, int pLen) + { + int correct = 0; + /* * Check if the first two bytes are 0 2 */ - correct |= (encoded[0] ^ 2); + correct |= (encoded[0] ^ 2); /* * Now the padding check, check for no 0 byte in the padding */ - int plen = encoded.length - ( - pLen /* Lenght of the PMS */ - + 1 /* Final 0-byte before PMS */ - ); - - for (int i = 1; i < plen; i++) { - int tmp = encoded[i]; - tmp |= tmp >> 1; - tmp |= tmp >> 2; - tmp |= tmp >> 4; - correct |= (tmp & 1) - 1; - } + int plen = encoded.length - ( + pLen /* Lenght of the PMS */ + + 1 /* Final 0-byte before PMS */ + ); + + for (int i = 1; i < plen; i++) + { + int tmp = encoded[i]; + tmp |= tmp >> 1; + tmp |= tmp >> 2; + tmp |= tmp >> 4; + correct |= (tmp & 1) - 1; + } /* * Make sure the padding ends with a 0 byte. */ - correct |= encoded[encoded.length - (pLen +1)]; + correct |= encoded[encoded.length - (pLen + 1)]; /* * Return 0 or 1, depending on the result. */ - correct |= correct >> 1; - correct |= correct >> 2; - correct |= correct >> 4; - return ~((correct & 1) - 1); - } - + correct |= correct >> 1; + correct |= correct >> 2; + correct |= correct >> 4; + return ~((correct & 1) - 1); + } + /** * Decode PKCS#1.5 encoding, and return a random value if the padding is not correct. - * - * @param in The encrypted block. + * + * @param in The encrypted block. * @param inOff Offset in the encrypted block. * @param inLen Length of the encrypted block. - * //@param pLen Length of the desired output. + * //@param pLen Length of the desired output. * @return The plaintext without padding, or a random value if the padding was incorrect. - * * @throws InvalidCipherTextException */ private byte[] decodeBlockOrRandom(byte[] in, int inOff, int inLen) @@ -291,7 +301,7 @@ } byte[] block = engine.processBlock(in, inOff, inLen); - byte[] random = null; + byte[] random; if (this.fallback == null) { random = new byte[this.pLen]; @@ -302,30 +312,12 @@ random = fallback; } - /* - * TODO: This is a potential dangerous side channel. However, you can - * fix this by changing the RSA engine in a way, that it will always - * return blocks of the same length and prepend them with 0 bytes if - * needed. - */ - if (block.length < getOutputBlockSize()) - { - throw new InvalidCipherTextException("block truncated"); - } - - /* - * TODO: Potential side channel. Fix it by making the engine always - * return blocks of the correct length. - */ - if (useStrictLength && block.length != engine.getOutputBlockSize()) - { - throw new InvalidCipherTextException("block incorrect size"); - } + byte[] data = (useStrictLength & (block.length != engine.getOutputBlockSize())) ? blockBuffer : block; /* * Check the padding. */ - int correct = PKCS1Encoding.checkPkcs1Encoding(block, this.pLen); + int correct = PKCS1Encoding.checkPkcs1Encoding(data, this.pLen); /* * Now, to a constant time constant memory copy of the decrypted value @@ -334,88 +326,106 @@ byte[] result = new byte[this.pLen]; for (int i = 0; i < this.pLen; i++) { - result[i] = (byte)((block[i + (block.length - pLen)] & (~correct)) | (random[i] & correct)); + result[i] = (byte)((data[i + (data.length - pLen)] & (~correct)) | (random[i] & correct)); } + Arrays.fill(data, (byte)0); + return result; } /** - * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format. + * @throws InvalidCipherTextException if the decrypted block is not in PKCS1 format. */ private byte[] decodeBlock( - byte[] in, - int inOff, - int inLen) + byte[] in, + int inOff, + int inLen) throws InvalidCipherTextException { /* * If the length of the expected plaintext is known, we use a constant-time decryption. * If the decryption fails, we return a random value. */ - if (this.pLen != -1) { - return this.decodeBlockOrRandom(in, inOff, inLen); - } - + if (this.pLen != -1) + { + return this.decodeBlockOrRandom(in, inOff, inLen); + } + byte[] block = engine.processBlock(in, inOff, inLen); + boolean incorrectLength = (useStrictLength & (block.length != engine.getOutputBlockSize())); + byte[] data; if (block.length < getOutputBlockSize()) { - throw new InvalidCipherTextException("block truncated"); + data = blockBuffer; + } + else + { + data = block; } - byte type = block[0]; + byte type = data[0]; + boolean badType; if (forPrivateKey) { - if (type != 2) - { - throw new InvalidCipherTextException("unknown block type"); - } + badType = (type != 2); } else { - if (type != 1) - { - throw new InvalidCipherTextException("unknown block type"); - } + badType = (type != 1); } - if (useStrictLength && block.length != engine.getOutputBlockSize()) - { - throw new InvalidCipherTextException("block incorrect size"); - } - // // find and extract the message block. // - int start; - - for (start = 1; start != block.length; start++) - { - byte pad = block[start]; - - if (pad == 0) - { - break; - } - if (type == 1 && pad != (byte)0xff) - { - throw new InvalidCipherTextException("block padding incorrect"); - } - } + int start = findStart(type, data); start++; // data should start at the next byte - if (start > block.length || start < HEADER_LENGTH) + if (badType | start < HEADER_LENGTH) + { + Arrays.fill(data, (byte)0); + throw new InvalidCipherTextException("block incorrect"); + } + + // if we get this far, it's likely to be a genuine encoding error + if (incorrectLength) { - throw new InvalidCipherTextException("no data in block"); + Arrays.fill(data, (byte)0); + throw new InvalidCipherTextException("block incorrect size"); } - byte[] result = new byte[block.length - start]; + byte[] result = new byte[data.length - start]; - System.arraycopy(block, start, result, 0, result.length); + System.arraycopy(data, start, result, 0, result.length); return result; } + + private int findStart(byte type, byte[] block) + throws InvalidCipherTextException + { + int start = -1; + boolean padErr = false; + + for (int i = 1; i != block.length; i++) + { + byte pad = block[i]; + + if (pad == 0 & start < 0) + { + start = i; + } + padErr |= (type == 1 & start < 0 & pad != (byte)0xff); + } + + if (padErr) + { + return -1; + } + + return start; + } } diff -Nru bouncycastle-1.55/core/src/main/j2me/org/bouncycastle/util/test/FixedSecureRandom.java bouncycastle-1.56/core/src/main/j2me/org/bouncycastle/util/test/FixedSecureRandom.java --- bouncycastle-1.55/core/src/main/j2me/org/bouncycastle/util/test/FixedSecureRandom.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/j2me/org/bouncycastle/util/test/FixedSecureRandom.java 2016-12-21 06:07:33.000000000 +0000 @@ -0,0 +1,325 @@ +package org.bouncycastle.util.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.SecureRandom; + +import org.bouncycastle.util.Pack; +import org.bouncycastle.util.encoders.Hex; + +/** + * A secure random that returns pre-seeded data to calls of nextBytes() or generateSeed(). + */ +public class FixedSecureRandom + extends SecureRandom +{ + private static java.math.BigInteger REGULAR = new java.math.BigInteger("01020304ffffffff0506070811111111", 16); + private static java.math.BigInteger ANDROID = new java.math.BigInteger("1111111105060708ffffffff01020304", 16); + private static java.math.BigInteger CLASSPATH = new java.math.BigInteger("3020104ffffffff05060708111111", 16); + + private static final boolean isAndroidStyle; + private static final boolean isClasspathStyle; + private static final boolean isRegularStyle; + + static + { + java.math.BigInteger check1 = new java.math.BigInteger(128, new RandomChecker()); + java.math.BigInteger check2 = new java.math.BigInteger(120, new RandomChecker()); + + isAndroidStyle = check1.equals(ANDROID); + isRegularStyle = check1.equals(REGULAR); + isClasspathStyle = check2.equals(CLASSPATH); + } + + private byte[] _data; + private int _index; + + /** + * Base class for sources of fixed "Randomness" + */ + public static class Source + { + byte[] data; + + Source(byte[] data) + { + this.data = data; + } + } + + /** + * Data Source - in this case we just expect requests for byte arrays. + */ + public static class Data + extends Source + { + public Data(byte[] data) + { + super(data); + } + } + + /** + * BigInteger Source - in this case we expect requests for data that will be used + * for BigIntegers. The FixedSecureRandom will attempt to compensate for platform differences here. + */ + public static class BigInteger + extends Source + { + public BigInteger(byte[] data) + { + super(data); + } + + public BigInteger(int bitLength, byte[] data) + { + super(expandToBitLength(bitLength, data)); + } + + public BigInteger(String hexData) + { + this(Hex.decode(hexData)); + } + + public BigInteger(int bitLength, String hexData) + { + super(expandToBitLength(bitLength, Hex.decode(hexData))); + } + } + + public FixedSecureRandom(byte[] value) + { + this(new Source[] { new Data(value) }); + } + + public FixedSecureRandom( + byte[][] values) + { + this(buildDataArray(values)); + } + + private static Data[] buildDataArray(byte[][] values) + { + Data[] res = new Data[values.length]; + + for (int i = 0; i != values.length; i++) + { + res[i] = new Data(values[i]); + } + + return res; + } + + public FixedSecureRandom( + Source[] sources) + { + super(new byte[0]); // to prevent recursion in provider creation + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + if (isRegularStyle) + { + if (isClasspathStyle) + { + for (int i = 0; i != sources.length; i++) + { + try + { + if (sources[i] instanceof BigInteger) + { + byte[] data = sources[i].data; + int len = data.length - (data.length % 4); + for (int w = data.length - len - 1; w >= 0; w--) + { + bOut.write(data[w]); + } + for (int w = data.length - len; w < data.length; w += 4) + { + bOut.write(data, w, 4); + } + } + else + { + bOut.write(sources[i].data); + } + } + catch (IOException e) + { + throw new IllegalArgumentException("can't save value source."); + } + } + } + else + { + for (int i = 0; i != sources.length; i++) + { + try + { + bOut.write(sources[i].data); + } + catch (IOException e) + { + throw new IllegalArgumentException("can't save value source."); + } + } + } + } + else if (isAndroidStyle) + { + for (int i = 0; i != sources.length; i++) + { + try + { + if (sources[i] instanceof BigInteger) + { + byte[] data = sources[i].data; + int len = data.length - (data.length % 4); + for (int w = 0; w < len; w += 4) + { + bOut.write(data, data.length - (w + 4), 4); + } + if (data.length - len != 0) + { + for (int w = 0; w != 4 - (data.length - len); w++) + { + bOut.write(0); + } + } + for (int w = 0; w != data.length - len; w++) + { + bOut.write(data[len + w]); + } + } + else + { + bOut.write(sources[i].data); + } + } + catch (IOException e) + { + throw new IllegalArgumentException("can't save value source."); + } + } + } + else + { + throw new IllegalStateException("Unrecognized BigInteger implementation"); + } + + _data = bOut.toByteArray(); + } + + public void nextBytes(byte[] bytes) + { + System.arraycopy(_data, _index, bytes, 0, bytes.length); + + _index += bytes.length; + } + + public byte[] generateSeed(int numBytes) + { + byte[] bytes = new byte[numBytes]; + + this.nextBytes(bytes); + + return bytes; + } + + // + // classpath's implementation of SecureRandom doesn't currently go back to nextBytes + // when next is called. We can't override next as it's a final method. + // + public int nextInt() + { + int val = 0; + + val |= nextValue() << 24; + val |= nextValue() << 16; + val |= nextValue() << 8; + val |= nextValue(); + + return val; + } + + // + // classpath's implementation of SecureRandom doesn't currently go back to nextBytes + // when next is called. We can't override next as it's a final method. + // + public long nextLong() + { + long val = 0; + + val |= (long)nextValue() << 56; + val |= (long)nextValue() << 48; + val |= (long)nextValue() << 40; + val |= (long)nextValue() << 32; + val |= (long)nextValue() << 24; + val |= (long)nextValue() << 16; + val |= (long)nextValue() << 8; + val |= (long)nextValue(); + + return val; + } + + public boolean isExhausted() + { + return _index == _data.length; + } + + private int nextValue() + { + return _data[_index++] & 0xff; + } + + private static class RandomChecker + extends SecureRandom + { + RandomChecker() + { + super(new byte[0]); // to prevent recursion in provider creation + } + + byte[] data = Hex.decode("01020304ffffffff0506070811111111"); + int index = 0; + + public void nextBytes(byte[] bytes) + { + System.arraycopy(data, index, bytes, 0, bytes.length); + + index += bytes.length; + } + } + + private static byte[] expandToBitLength(int bitLength, byte[] v) + { + if ((bitLength + 7) / 8 > v.length) + { + byte[] tmp = new byte[(bitLength + 7) / 8]; + + System.arraycopy(v, 0, tmp, tmp.length - v.length, v.length); + if (isAndroidStyle) + { + if (bitLength % 8 != 0) + { + int i = Pack.bigEndianToInt(tmp, 0); + Pack.intToBigEndian(i << (8 - (bitLength % 8)), tmp, 0); + } + } + + return tmp; + } + else + { + if (isAndroidStyle && bitLength < (v.length * 8)) + { + if (bitLength % 8 != 0) + { + int i = Pack.bigEndianToInt(v, 0); + Pack.intToBigEndian(i << (8 - (bitLength % 8)), v, 0); + } + } + } + + return v; + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java 2016-06-23 03:39:12.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java 2016-10-14 23:22:25.000000000 +0000 @@ -99,6 +99,17 @@ public ASN1Enumerated( byte[] bytes) { + if (bytes.length > 1) + { + if (bytes[0] == 0 && (bytes[1] & 0x80) == 0) + { + throw new IllegalArgumentException("malformed enumerated"); + } + if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0) + { + throw new IllegalArgumentException("malformed enumerated"); + } + } this.bytes = Arrays.clone(bytes); } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java 2015-10-05 20:51:13.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java 2016-10-15 01:40:49.000000000 +0000 @@ -89,6 +89,17 @@ ASN1Integer(byte[] bytes, boolean clone) { + if (bytes.length > 1) + { + if (bytes[0] == 0 && (bytes[1] & 0x80) == 0) + { + throw new IllegalArgumentException("malformed integer"); + } + if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0) + { + throw new IllegalArgumentException("malformed integer"); + } + } this.bytes = (clone) ? Arrays.clone(bytes) : bytes; } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java 2015-10-08 23:49:32.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java 2016-08-22 23:44:28.000000000 +0000 @@ -3,8 +3,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; -import java.util.HashMap; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.bouncycastle.util.Arrays; @@ -20,9 +20,10 @@ /** * return an OID from the passed in object + * * @param obj an ASN1ObjectIdentifier or an object that can be converted into one. - * @throws IllegalArgumentException if the object cannot be converted. * @return an ASN1ObjectIdentifier instance, or null. + * @throws IllegalArgumentException if the object cannot be converted. */ public static ASN1ObjectIdentifier getInstance( Object obj) @@ -59,9 +60,9 @@ * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly * tagged false otherwise. + * @return an ASN1ObjectIdentifier instance, or null. * @throws IllegalArgumentException if the tagged object cannot * be converted. - * @return an ASN1ObjectIdentifier instance, or null. */ public static ASN1ObjectIdentifier getInstance( ASN1TaggedObject obj, @@ -178,12 +179,12 @@ this.identifier = identifier; } - /** - * Create an OID that creates a branch under the current one. - * - * @param branchID node numbers for the new branch. - * @return the OID for the new created branch. - */ + /** + * Create an OID that creates a branch under the current one. + * + * @param branchID node numbers for the new branch. + * @return the OID for the new created branch. + */ ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branchID) { if (!isValidBranchID(branchID, 0)) @@ -416,32 +417,29 @@ * The pool is also used by the ASN.1 parsers to limit the number of duplicated OID * objects in circulation. *

+ * * @return a reference to the identifier in the pool. */ public ASN1ObjectIdentifier intern() { - synchronized (pool) + final OidHandle hdl = new OidHandle(getBody()); + ASN1ObjectIdentifier oid = pool.get(hdl); + if (oid == null) { - OidHandle hdl = new OidHandle(getBody()); - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)pool.get(hdl); - - if (oid != null) - { - return oid; - } - else + oid = pool.putIfAbsent(hdl, this); + if (oid == null) { - pool.put(hdl, this); - return this; + oid = this; } } + return oid; } - private static final Map pool = new HashMap(); + private static final ConcurrentMap pool = new ConcurrentHashMap(); private static class OidHandle { - private int key; + private final int key; private final byte[] enc; OidHandle(byte[] enc) @@ -468,17 +466,12 @@ static ASN1ObjectIdentifier fromOctetString(byte[] enc) { - OidHandle hdl = new OidHandle(enc); - - synchronized (pool) + final OidHandle hdl = new OidHandle(enc); + ASN1ObjectIdentifier oid = pool.get(hdl); + if (oid == null) { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)pool.get(hdl); - if (oid != null) - { - return oid; - } + return new ASN1ObjectIdentifier(enc); } - - return new ASN1ObjectIdentifier(enc); + return oid; } } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java 2016-12-16 23:04:37.000000000 +0000 @@ -0,0 +1,71 @@ +package org.bouncycastle.asn1.bc; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + *
+ * EncryptedObjectStoreData ::= SEQUENCE {
+ *     encryptionAlgorithm AlgorithmIdentifier
+ *     encryptedContent OCTET STRING
+ * }
+ * 
+ */ +public class EncryptedObjectStoreData + extends ASN1Object +{ + private final AlgorithmIdentifier encryptionAlgorithm; + private final ASN1OctetString encryptedContent; + + public EncryptedObjectStoreData(AlgorithmIdentifier encryptionAlgorithm, byte[] encryptedContent) + { + this.encryptionAlgorithm = encryptionAlgorithm; + this.encryptedContent = new DEROctetString(encryptedContent); + } + + private EncryptedObjectStoreData(ASN1Sequence seq) + { + this.encryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + this.encryptedContent = ASN1OctetString.getInstance(seq.getObjectAt(1)); + } + + public static EncryptedObjectStoreData getInstance(Object o) + { + if (o instanceof EncryptedObjectStoreData) + { + return (EncryptedObjectStoreData)o; + } + else if (o != null) + { + return new EncryptedObjectStoreData(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1OctetString getEncryptedContent() + { + return encryptedContent; + } + + public AlgorithmIdentifier getEncryptionAlgorithm() + { + return encryptionAlgorithm; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(encryptionAlgorithm); + v.add(encryptedContent); + + return new DERSequence(v); + } +} \ No newline at end of file diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java 2016-12-16 23:04:37.000000000 +0000 @@ -0,0 +1,80 @@ +package org.bouncycastle.asn1.bc; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import org.bouncycastle.asn1.x509.Certificate; + +/** + *
+ *     EncryptedPrivateKeyObjectData ::= SEQUENCE {
+ *         encryptedPrivateKeyInfo EncryptedPrivateKeyInfo,
+ *         certificates SEQUENCE OF Certificate
+ *     }
+ * 
+ */ +public class EncryptedPrivateKeyData + extends ASN1Object +{ + private final EncryptedPrivateKeyInfo encryptedPrivateKeyInfo; + private final Certificate[] certificateChain; + + public EncryptedPrivateKeyData(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo, Certificate[] certificateChain) + { + this.encryptedPrivateKeyInfo = encryptedPrivateKeyInfo; + this.certificateChain = new Certificate[certificateChain.length]; + System.arraycopy(certificateChain, 0, this.certificateChain, 0, certificateChain.length); + } + + private EncryptedPrivateKeyData(ASN1Sequence seq) + { + encryptedPrivateKeyInfo = EncryptedPrivateKeyInfo.getInstance(seq.getObjectAt(0)); + ASN1Sequence certSeq = ASN1Sequence.getInstance(seq.getObjectAt(1)); + certificateChain = new Certificate[certSeq.size()]; + for (int i = 0; i != certificateChain.length; i++) + { + certificateChain[i] = Certificate.getInstance(certSeq.getObjectAt(i)); + } + } + + public static EncryptedPrivateKeyData getInstance(Object o) + { + if (o instanceof EncryptedPrivateKeyData) + { + return (EncryptedPrivateKeyData)o; + } + else if (o != null) + { + return new EncryptedPrivateKeyData(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public Certificate[] getCertificateChain() + { + Certificate[] tmp = new Certificate[certificateChain.length]; + + System.arraycopy(certificateChain, 0, tmp, 0, certificateChain.length); + + return tmp; + } + + public EncryptedPrivateKeyInfo getEncryptedPrivateKeyInfo() + { + return encryptedPrivateKeyInfo; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(encryptedPrivateKeyInfo); + v.add(new DERSequence(certificateChain)); + + return new DERSequence(v); + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java 2016-12-16 23:04:37.000000000 +0000 @@ -0,0 +1,73 @@ +package org.bouncycastle.asn1.bc; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.util.Arrays; + +/** + *
+ *     EncryptedSecretKeyData ::= SEQUENCE {
+ *         keyEncryptionAlgorithm AlgorithmIdentifier,
+ *         encryptedKeyData OCTET STRING
+ *     }
+ * 
+ */ +public class EncryptedSecretKeyData + extends ASN1Object +{ + private final AlgorithmIdentifier keyEncryptionAlgorithm; + private final ASN1OctetString encryptedKeyData; + + public EncryptedSecretKeyData(AlgorithmIdentifier keyEncryptionAlgorithm, byte[] encryptedKeyData) + { + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKeyData = new DEROctetString(Arrays.clone(encryptedKeyData)); + } + + private EncryptedSecretKeyData(ASN1Sequence seq) + { + this.keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + this.encryptedKeyData = ASN1OctetString.getInstance(seq.getObjectAt(1)); + } + + public static EncryptedSecretKeyData getInstance(Object o) + { + if (o instanceof EncryptedSecretKeyData) + { + return (EncryptedSecretKeyData)o; + } + else if (o != null) + { + return new EncryptedSecretKeyData(ASN1Sequence.getInstance(o)); + } + + return null; + } + + + public AlgorithmIdentifier getKeyEncryptionAlgorithm() + { + return keyEncryptionAlgorithm; + } + + public byte[] getEncryptedKeyData() + { + return Arrays.clone(encryptedKeyData.getOctets()); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(keyEncryptionAlgorithm); + v.add(encryptedKeyData); + + return new DERSequence(v); + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/ObjectData.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/ObjectData.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/ObjectData.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/ObjectData.java 2016-12-08 02:22:21.000000000 +0000 @@ -0,0 +1,123 @@ +package org.bouncycastle.asn1.bc; + +import java.math.BigInteger; +import java.util.Date; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.util.Arrays; + +/** + *
+ * ObjectData ::= SEQUENCE {
+ *     type             INTEGER,
+ *     identifier       UTF8String,
+ *     creationDate     GeneralizedTime,
+ *     lastModifiedDate GeneralizedTime,
+ *     data             OCTET STRING,
+ *     comment          UTF8String OPTIONAL
+ * }
+ * 
+ */ +public class ObjectData + extends ASN1Object +{ + private final BigInteger type; + private final String identifier; + private final ASN1GeneralizedTime creationDate; + private final ASN1GeneralizedTime lastModifiedDate; + private final ASN1OctetString data; + private final String comment; + + private ObjectData(ASN1Sequence seq) + { + this.type = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue(); + this.identifier = DERUTF8String.getInstance(seq.getObjectAt(1)).getString(); + this.creationDate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(2)); + this.lastModifiedDate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(3)); + this.data = ASN1OctetString.getInstance(seq.getObjectAt(4)); + this.comment = (seq.size() == 6) ? DERUTF8String.getInstance(seq.getObjectAt(5)).getString() : null; + } + + public ObjectData(BigInteger type, String identifier, Date creationDate, Date lastModifiedDate, byte[] data, String comment) + { + this.type = type; + this.identifier = identifier; + this.creationDate = new DERGeneralizedTime(creationDate); + this.lastModifiedDate = new DERGeneralizedTime(lastModifiedDate); + this.data = new DEROctetString(Arrays.clone(data)); + this.comment = comment; + } + + public static ObjectData getInstance( + Object obj) + { + if (obj instanceof ObjectData) + { + return (ObjectData)obj; + } + else if (obj != null) + { + return new ObjectData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public String getComment() + { + return comment; + } + + public ASN1GeneralizedTime getCreationDate() + { + return creationDate; + } + + public byte[] getData() + { + return Arrays.clone(data.getOctets()); + } + + public String getIdentifier() + { + return identifier; + } + + public ASN1GeneralizedTime getLastModifiedDate() + { + return lastModifiedDate; + } + + public BigInteger getType() + { + return type; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(type)); + v.add(new DERUTF8String(identifier)); + v.add(creationDate); + v.add(lastModifiedDate); + v.add(data); + + if (comment != null) + { + v.add(new DERUTF8String(comment)); + } + + return new DERSequence(v); + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/ObjectDataSequence.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/ObjectDataSequence.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/ObjectDataSequence.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/ObjectDataSequence.java 2015-08-05 06:39:46.000000000 +0000 @@ -0,0 +1,64 @@ +package org.bouncycastle.asn1.bc; + +import java.util.Iterator; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.util.Arrays; + +/** + *
+ * ObjectDataSequence ::= SEQUENCE OF ObjectData
+ * 
+ */ +public class ObjectDataSequence + extends ASN1Object + implements org.bouncycastle.util.Iterable +{ + private final ASN1Encodable[] dataSequence; + + public ObjectDataSequence(ObjectData[] dataSequence) + { + this.dataSequence = new ASN1Encodable[dataSequence.length]; + + System.arraycopy(dataSequence, 0, this.dataSequence, 0, dataSequence.length); + } + + private ObjectDataSequence(ASN1Sequence seq) + { + dataSequence = new ASN1Encodable[seq.size()]; + + for (int i = 0; i != dataSequence.length; i++) + { + dataSequence[i] = ObjectData.getInstance(seq.getObjectAt(i)); + } + } + + public static ObjectDataSequence getInstance( + Object obj) + { + if (obj instanceof ObjectDataSequence) + { + return (ObjectDataSequence)obj; + } + else if (obj != null) + { + return new ObjectDataSequence(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(dataSequence); + } + + public Iterator iterator() + { + return new Arrays.Iterator(dataSequence); + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreData.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreData.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreData.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreData.java 2015-08-05 06:39:46.000000000 +0000 @@ -0,0 +1,121 @@ +package org.bouncycastle.asn1.bc; + +import java.math.BigInteger; +import java.util.Date; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + *
+ * ObjectStoreData ::= SEQUENCE {
+ *     version INTEGER.
+ *     dataSalt OCTET STRING,
+ *     integrityAlgorithm AlgorithmIdentifier,
+ *     creationDate GeneralizedTime,
+ *     lastModifiedDate GeneralizedTime,
+ *     objectDataSequence ObjectDataSequence,
+ *     comment UTF8String OPTIONAL
+ * }
+ * 
+ */ +public class ObjectStoreData + extends ASN1Object +{ + private final BigInteger version; + private final AlgorithmIdentifier integrityAlgorithm; + private final ASN1GeneralizedTime creationDate; + private final ASN1GeneralizedTime lastModifiedDate; + private final ObjectDataSequence objectDataSequence; + private final String comment; + + public ObjectStoreData(AlgorithmIdentifier integrityAlgorithm, Date creationDate, Date lastModifiedDate, ObjectDataSequence objectDataSequence, String comment) + { + this.version = BigInteger.valueOf(1); + this.integrityAlgorithm = integrityAlgorithm; + this.creationDate = new DERGeneralizedTime(creationDate); + this.lastModifiedDate = new DERGeneralizedTime(lastModifiedDate); + this.objectDataSequence = objectDataSequence; + this.comment = comment; + } + + private ObjectStoreData(ASN1Sequence seq) + { + this.version = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue(); + this.integrityAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + this.creationDate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(2)); + this.lastModifiedDate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(3)); + this.objectDataSequence = ObjectDataSequence.getInstance(seq.getObjectAt(4)); + this.comment = (seq.size() == 6) ? DERUTF8String.getInstance(seq.getObjectAt(5)).getString() : null; + } + + public static ObjectStoreData getInstance(Object o) + { + if (o instanceof ObjectStoreData) + { + return (ObjectStoreData)o; + } + else if (o != null) + { + return new ObjectStoreData(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public String getComment() + { + return comment; + } + + public ASN1GeneralizedTime getCreationDate() + { + return creationDate; + } + + public AlgorithmIdentifier getIntegrityAlgorithm() + { + return integrityAlgorithm; + } + + public ASN1GeneralizedTime getLastModifiedDate() + { + return lastModifiedDate; + } + + public ObjectDataSequence getObjectDataSequence() + { + return objectDataSequence; + } + + public BigInteger getVersion() + { + return version; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(version)); + v.add(integrityAlgorithm); + v.add(creationDate); + v.add(lastModifiedDate); + v.add(objectDataSequence); + + if (comment != null) + { + v.add(new DERUTF8String(comment)); + } + + return new DERSequence(v); + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java 2015-08-05 06:39:46.000000000 +0000 @@ -0,0 +1,85 @@ +package org.bouncycastle.asn1.bc; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; + +/** + *
+ * ObjectStoreIntegrityCheck ::= CHOICE {
+ *     PbeMacIntegrityCheck
+ * }
+ * 
+ */ +public class ObjectStoreIntegrityCheck + extends ASN1Object + implements ASN1Choice +{ + public static final int PBKD_MAC_CHECK = 0; + + private final int type; + private final ASN1Object integrityCheck; + + public ObjectStoreIntegrityCheck(PbkdMacIntegrityCheck macIntegrityCheck) + { + this((ASN1Encodable)macIntegrityCheck); + } + + private ObjectStoreIntegrityCheck(ASN1Encodable obj) + { + if (obj instanceof ASN1Sequence || obj instanceof PbkdMacIntegrityCheck) + { + this.type = PBKD_MAC_CHECK; + this.integrityCheck = PbkdMacIntegrityCheck.getInstance(obj); + } + else + { + throw new IllegalArgumentException("Unknown check object in integrity check."); + } + } + + public static ObjectStoreIntegrityCheck getInstance(Object o) + { + if (o instanceof ObjectStoreIntegrityCheck) + { + return (ObjectStoreIntegrityCheck)o; + } + else if (o instanceof byte[]) + { + try + { + return new ObjectStoreIntegrityCheck(ASN1Primitive.fromByteArray((byte[])o)); + } + catch (IOException e) + { + throw new IllegalArgumentException("Unable to parse integrity check details."); + } + } + else if (o != null) + { + return new ObjectStoreIntegrityCheck((ASN1Encodable)(o)); + } + + return null; + } + + + public int getType() + { + return type; + } + + public ASN1Object getIntegrityCheck() + { + return integrityCheck; + } + + public ASN1Primitive toASN1Primitive() + { + return integrityCheck.toASN1Primitive(); + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStore.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStore.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStore.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/ObjectStore.java 2015-04-20 19:44:35.000000000 +0000 @@ -0,0 +1,101 @@ +package org.bouncycastle.asn1.bc; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + *
+ * ObjectStore ::= SEQUENCE {
+ *     CHOICE {
+ *          encryptedObjectStoreData EncryptedObjectStoreData,
+ *          objectStoreData ObjectStoreData
+ *     }
+ *     integrityCheck ObjectStoreIntegrityCheck
+ * }
+ * 
+ */ +public class ObjectStore + extends ASN1Object +{ + private final ASN1Encodable storeData; + private final ObjectStoreIntegrityCheck integrityCheck; + + public ObjectStore(ObjectStoreData objectStoreData, ObjectStoreIntegrityCheck integrityCheck) + { + this.storeData = objectStoreData; + this.integrityCheck = integrityCheck; + } + + + public ObjectStore(EncryptedObjectStoreData encryptedObjectStoreData, ObjectStoreIntegrityCheck integrityCheck) + { + this.storeData = encryptedObjectStoreData; + this.integrityCheck = integrityCheck; + } + + private ObjectStore(ASN1Sequence seq) + { + ASN1Encodable sData = seq.getObjectAt(0); + if (sData instanceof EncryptedObjectStoreData) + { + this.storeData = sData; + } + else if (sData instanceof ObjectStoreData) + { + this.storeData = sData; + } + else + { + ASN1Sequence seqData = ASN1Sequence.getInstance(sData); + + if (seqData.size() == 2) + { + this.storeData = EncryptedObjectStoreData.getInstance(seqData); + } + else + { + this.storeData = ObjectStoreData.getInstance(seqData); + } + } + + this.integrityCheck = ObjectStoreIntegrityCheck.getInstance(seq.getObjectAt(1)); + } + + public static ObjectStore getInstance(Object o) + { + if (o instanceof ObjectStore) + { + return (ObjectStore)o; + } + else if (o != null) + { + return new ObjectStore(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ObjectStoreIntegrityCheck getIntegrityCheck() + { + return integrityCheck; + } + + public ASN1Encodable getStoreData() + { + return storeData; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(storeData); + v.add(integrityCheck); + + return new DERSequence(v); + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java 2016-12-16 23:03:59.000000000 +0000 @@ -0,0 +1,83 @@ +package org.bouncycastle.asn1.bc; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.pkcs.KeyDerivationFunc; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.util.Arrays; + +/** + *
+ * PbkdMacIntegrityCheck ::= SEQUENCE {
+ *     macAlgorithm AlgorithmIdentifier,
+ *     pbkdAlgorithm KeyDerivationFunc,
+ *     mac OCTET STRING
+ * }
+ * 
+ */ +public class PbkdMacIntegrityCheck + extends ASN1Object +{ + private final AlgorithmIdentifier macAlgorithm; + private final KeyDerivationFunc pbkdAlgorithm; + private final ASN1OctetString mac; + + public PbkdMacIntegrityCheck(AlgorithmIdentifier macAlgorithm, KeyDerivationFunc pbkdAlgorithm, byte[] mac) + { + this.macAlgorithm = macAlgorithm; + this.pbkdAlgorithm = pbkdAlgorithm; + this.mac = new DEROctetString(Arrays.clone(mac)); + } + + private PbkdMacIntegrityCheck(ASN1Sequence seq) + { + this.macAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + this.pbkdAlgorithm = KeyDerivationFunc.getInstance(seq.getObjectAt(1)); + this.mac = ASN1OctetString.getInstance(seq.getObjectAt(2)); + } + + public static PbkdMacIntegrityCheck getInstance(Object o) + { + if (o instanceof PbkdMacIntegrityCheck) + { + return (PbkdMacIntegrityCheck)o; + } + else if (o != null) + { + return new PbkdMacIntegrityCheck(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public AlgorithmIdentifier getMacAlgorithm() + { + return macAlgorithm; + } + + public KeyDerivationFunc getPbkdAlgorithm() + { + return pbkdAlgorithm; + } + + public byte[] getMac() + { + return Arrays.clone(mac.getOctets()); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(macAlgorithm); + v.add(pbkdAlgorithm); + v.add(mac); + + return new DERSequence(v); + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/SecretKeyData.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/SecretKeyData.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/bc/SecretKeyData.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/bc/SecretKeyData.java 2016-12-16 23:03:22.000000000 +0000 @@ -0,0 +1,72 @@ +package org.bouncycastle.asn1.bc; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.util.Arrays; + +/** + *
+ *     SecretKeyData ::= SEQUENCE {
+ *         keyAlgorithm OBJECT IDENTIFIER,
+ *         keyBytes OCTET STRING
+ *     }
+ * 
+ */ +public class SecretKeyData + extends ASN1Object +{ + private final ASN1ObjectIdentifier keyAlgorithm; + private final ASN1OctetString keyBytes; + + public SecretKeyData(ASN1ObjectIdentifier keyAlgorithm, byte[] keyBytes) + { + this.keyAlgorithm = keyAlgorithm; + this.keyBytes = new DEROctetString(Arrays.clone(keyBytes)); + } + + private SecretKeyData(ASN1Sequence seq) + { + this.keyAlgorithm = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + this.keyBytes = ASN1OctetString.getInstance(seq.getObjectAt(1)); + } + + public static SecretKeyData getInstance(Object o) + { + if (o instanceof SecretKeyData) + { + return (SecretKeyData)o; + } + else if (o != null) + { + return new SecretKeyData(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public byte[] getKeyBytes() + { + return Arrays.clone(keyBytes.getOctets()); + } + + public ASN1ObjectIdentifier getKeyAlgorithm() + { + return keyAlgorithm; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(keyAlgorithm); + v.add(keyBytes); + + return new DERSequence(v); + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java 2016-06-23 02:50:10.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java 2016-08-26 22:22:06.000000000 +0000 @@ -13,7 +13,7 @@ implements ASN1Choice { private int tagNo; - private ASN1Encodable value; + private ASN1Encodable value; /** * create a CertStatus object with a tag of zero. @@ -54,6 +54,7 @@ break; case 2: value = DERNull.INSTANCE; + break; default: throw new IllegalArgumentException("Unknown tag encountered: " + choice.getTagNo()); } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java 2015-12-04 01:42:20.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java 2016-09-10 03:08:00.000000000 +0000 @@ -39,6 +39,10 @@ static final ASN1ObjectIdentifier sha512WithRSAEncryption = pkcs_1.branch("13"); /** PKCS#1: 1.2.840.113549.1.1.14 */ static final ASN1ObjectIdentifier sha224WithRSAEncryption = pkcs_1.branch("14"); + /** PKCS#1: 1.2.840.113549.1.1.15 */ + ASN1ObjectIdentifier sha512_224WithRSAEncryption = pkcs_1.branch("15"); + /** PKCS#1: 1.2.840.113549.1.1.16 */ + ASN1ObjectIdentifier sha512_256WithRSAEncryption = pkcs_1.branch("16"); // // pkcs-3 OBJECT IDENTIFIER ::= { diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java 2015-10-06 00:35:41.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java 2016-08-22 23:27:40.000000000 +0000 @@ -78,59 +78,50 @@ /** * businessCategory - DirectoryString(SIZE(1..128) */ - public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier( - "2.5.4.15").intern(); + public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier("2.5.4.15").intern(); /** * postalCode - DirectoryString(SIZE(1..40) */ - public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier( - "2.5.4.17").intern(); + public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier("2.5.4.17").intern(); /** * dnQualifier - DirectoryString(SIZE(1..64) */ - public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier( - "2.5.4.46").intern(); + public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier("2.5.4.46").intern(); /** * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) */ - public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier( - "2.5.4.65").intern(); + public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier("2.5.4.65").intern(); /** * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z */ - public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier( - "1.3.6.1.5.5.7.9.1").intern(); + public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.1").intern(); /** * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) */ - public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier( - "1.3.6.1.5.5.7.9.2").intern(); + public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.2").intern(); /** * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" */ - public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier( - "1.3.6.1.5.5.7.9.3").intern(); + public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.3").intern(); /** * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 * codes only */ - public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier( - "1.3.6.1.5.5.7.9.4").intern(); + public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.4").intern(); /** * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166 * codes only */ - public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier( - "1.3.6.1.5.5.7.9.5").intern(); + public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.5").intern(); /** diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/x509/Extension.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/x509/Extension.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/asn1/x509/Extension.java 2015-10-06 00:29:45.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/asn1/x509/Extension.java 2016-11-02 23:16:34.000000000 +0000 @@ -174,6 +174,11 @@ */ public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55").intern(); + /** + * Expired Certificates on CRL extension + */ + public static final ASN1ObjectIdentifier expiredCertsOnCRL = new ASN1ObjectIdentifier("2.5.29.60").intern(); + private ASN1ObjectIdentifier extnId; private boolean critical; private ASN1OctetString value; diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java 2013-07-26 05:06:42.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java 2016-10-29 03:10:36.000000000 +0000 @@ -6,11 +6,11 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.generators.DHKeyPairGenerator; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.DHKeyGenerationParameters; import org.bouncycastle.crypto.params.DHParameters; -import org.bouncycastle.crypto.params.DHPublicKeyParameters; import org.bouncycastle.crypto.params.DHPrivateKeyParameters; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.DHPublicKeyParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; /** @@ -26,6 +26,8 @@ */ public class DHAgreement { + private static final BigInteger ONE = BigInteger.valueOf(1); + private DHPrivateKeyParameters key; private DHParameters dhParams; private BigInteger privateValue; @@ -89,6 +91,12 @@ BigInteger p = dhParams.getP(); - return message.modPow(key.getX(), p).multiply(pub.getY().modPow(privateValue, p)).mod(p); + BigInteger result = pub.getY().modPow(privateValue, p); + if (result.compareTo(ONE) == 0) + { + throw new IllegalStateException("Shared key can't be 1"); + } + + return message.modPow(key.getX(), p).multiply(result).mod(p); } } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java 2013-07-26 05:06:41.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java 2016-10-29 03:10:36.000000000 +0000 @@ -20,6 +20,8 @@ public class DHBasicAgreement implements BasicAgreement { + private static final BigInteger ONE = BigInteger.valueOf(1); + private DHPrivateKeyParameters key; private DHParameters dhParams; @@ -66,6 +68,12 @@ throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters."); } - return pub.getY().modPow(key.getX(), dhParams.getP()); + BigInteger result = pub.getY().modPow(key.getX(), dhParams.getP()); + if (result.compareTo(ONE) == 0) + { + throw new IllegalStateException("Shared key can't be 1"); + } + + return result; } } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/agreement/DHStandardGroups.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/agreement/DHStandardGroups.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/agreement/DHStandardGroups.java 2014-09-05 05:20:45.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/agreement/DHStandardGroups.java 2016-10-25 05:58:45.000000000 +0000 @@ -162,6 +162,10 @@ + "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A" + "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24" + "855E6EEB22B3B2E5"; private static final String rfc5114_1024_160_q = "F518AA8781A8DF278ABA4E7D64B7CB9D49462353"; + + /** + * @deprecated Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf + */ public static final DHParameters rfc5114_1024_160 = fromPGQ(rfc5114_1024_160_p, rfc5114_1024_160_g, rfc5114_1024_160_q); @@ -178,6 +182,10 @@ + "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381" + "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269" + "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179" + "81BC087F2A7065B384B890D3191F2BFA"; private static final String rfc5114_2048_224_q = "801C0D34C58D93FE997177101F80535A4738CEBCBF389A99B36371EB"; + + /** + * @deprecated Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf + */ public static final DHParameters rfc5114_2048_224 = fromPGQ(rfc5114_2048_224_p, rfc5114_2048_224_g, rfc5114_2048_224_q); @@ -195,6 +203,10 @@ + "184B523D1DB246C32F63078490F00EF8D647D148D4795451" + "5E2327CFEF98C582664B4C0F6CC41659"; private static final String rfc5114_2048_256_q = "8CF83642A709A097B447997640129DA299B1A47D1EB3750B" + "A308B0FE64F5FBD3"; + + /** + * @deprecated Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf + */ public static final DHParameters rfc5114_2048_256 = fromPGQ(rfc5114_2048_256_p, rfc5114_2048_256_g, rfc5114_2048_256_q); diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java 2016-08-17 02:03:54.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java 2016-12-22 00:30:25.000000000 +0000 @@ -7,8 +7,9 @@ import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.util.DigestFactory; +import org.bouncycastle.util.Arrays; /** * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2. @@ -26,7 +27,7 @@ public OAEPEncoding( AsymmetricBlockCipher cipher) { - this(cipher, new SHA1Digest(), null); + this(cipher, DigestFactory.createSHA1(), null); } public OAEPEncoding( @@ -212,28 +213,17 @@ throws InvalidCipherTextException { byte[] data = engine.processBlock(in, inOff, inLen); - byte[] block; + byte[] block = new byte[engine.getOutputBlockSize()]; // // as we may have zeros in our leading bytes for the block we produced // on encryption, we need to make sure our decrypted block comes back // the same size. // - if (data.length < engine.getOutputBlockSize()) - { - block = new byte[engine.getOutputBlockSize()]; - System.arraycopy(data, 0, block, block.length - data.length, data.length); - } - else - { - block = data; - } + System.arraycopy(data, 0, block, block.length - data.length, data.length); - if (block.length < (2 * defHash.length) + 1) - { - throw new InvalidCipherTextException("data too short"); - } + boolean shortData = (block.length < (2 * defHash.length) + 1); // // unmask the seed. @@ -270,31 +260,29 @@ } } - if (defHashWrong) - { - throw new InvalidCipherTextException("data hash wrong"); - } - // // find the data block // - int start; + int start = block.length; - for (start = 2 * defHash.length; start != block.length; start++) + for (int index = 2 * defHash.length; index != block.length; index++) { - if (block[start] != 0) + if (block[index] != 0 & start == block.length) { - break; + start = index; } } - if (start > (block.length - 1) || block[start] != 1) - { - throw new InvalidCipherTextException("data start wrong " + start); - } + boolean dataStartWrong = (start > (block.length - 1) | block[start] != 1); start++; + if (defHashWrong | shortData | dataStartWrong) + { + Arrays.fill(block, (byte)0); + throw new InvalidCipherTextException("data wrong"); + } + // // extract the data block // diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java 2016-02-16 00:28:40.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java 2016-08-28 23:39:20.000000000 +0000 @@ -9,6 +9,7 @@ import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.util.Arrays; /** * this does your basic PKCS 1 v1.5 padding - whether or not you should be using this @@ -34,33 +35,35 @@ private static final int HEADER_LENGTH = 10; - private SecureRandom random; - private AsymmetricBlockCipher engine; - private boolean forEncryption; - private boolean forPrivateKey; - private boolean useStrictLength; - private int pLen = -1; - private byte[] fallback = null; + private SecureRandom random; + private AsymmetricBlockCipher engine; + private boolean forEncryption; + private boolean forPrivateKey; + private boolean useStrictLength; + private int pLen = -1; + private byte[] fallback = null; + private byte[] blockBuffer; /** * Basic constructor. + * * @param cipher */ public PKCS1Encoding( - AsymmetricBlockCipher cipher) + AsymmetricBlockCipher cipher) { this.engine = cipher; this.useStrictLength = useStrict(); - } + } /** * Constructor for decryption with a fixed plaintext length. - * + * * @param cipher The cipher to use for cryptographic operation. - * @param pLen Length of the expected plaintext. + * @param pLen Length of the expected plaintext. */ public PKCS1Encoding( - AsymmetricBlockCipher cipher, + AsymmetricBlockCipher cipher, int pLen) { this.engine = cipher; @@ -68,27 +71,24 @@ this.pLen = pLen; } - /** - * Constructor for decryption with a fixed plaintext length and a fallback - * value that is returned, if the padding is incorrect. - * - * @param cipher - * The cipher to use for cryptographic operation. - * @param fallback - * The fallback value, we don't do an arraycopy here. - */ - public PKCS1Encoding( - AsymmetricBlockCipher cipher, + /** + * Constructor for decryption with a fixed plaintext length and a fallback + * value that is returned, if the padding is incorrect. + * + * @param cipher The cipher to use for cryptographic operation. + * @param fallback The fallback value, we don't do an arraycopy here. + */ + public PKCS1Encoding( + AsymmetricBlockCipher cipher, byte[] fallback) { - this.engine = cipher; - this.useStrictLength = useStrict(); - this.fallback = fallback; - this.pLen = fallback.length; + this.engine = cipher; + this.useStrictLength = useStrict(); + this.fallback = fallback; + this.pLen = fallback.length; } - - + // // for J2ME compatibility // @@ -124,14 +124,14 @@ } public void init( - boolean forEncryption, - CipherParameters param) + boolean forEncryption, + CipherParameters param) { - AsymmetricKeyParameter kParam; + AsymmetricKeyParameter kParam; if (param instanceof ParametersWithRandom) { - ParametersWithRandom rParam = (ParametersWithRandom)param; + ParametersWithRandom rParam = (ParametersWithRandom)param; this.random = rParam.getRandom(); kParam = (AsymmetricKeyParameter)rParam.getParameters(); @@ -149,11 +149,17 @@ this.forPrivateKey = kParam.isPrivate(); this.forEncryption = forEncryption; + this.blockBuffer = new byte[engine.getOutputBlockSize()]; + + if (pLen > 0 && fallback == null && random == null) + { + throw new IllegalArgumentException("encoder requires random"); + } } public int getInputBlockSize() { - int baseBlockSize = engine.getInputBlockSize(); + int baseBlockSize = engine.getInputBlockSize(); if (forEncryption) { @@ -167,7 +173,7 @@ public int getOutputBlockSize() { - int baseBlockSize = engine.getOutputBlockSize(); + int baseBlockSize = engine.getOutputBlockSize(); if (forEncryption) { @@ -180,9 +186,9 @@ } public byte[] processBlock( - byte[] in, - int inOff, - int inLen) + byte[] in, + int inOff, + int inLen) throws InvalidCipherTextException { if (forEncryption) @@ -196,17 +202,17 @@ } private byte[] encodeBlock( - byte[] in, - int inOff, - int inLen) + byte[] in, + int inOff, + int inLen) throws InvalidCipherTextException { if (inLen > getInputBlockSize()) { throw new IllegalArgumentException("input data too large"); } - - byte[] block = new byte[engine.getInputBlockSize()]; + + byte[] block = new byte[engine.getInputBlockSize()]; if (forPrivateKey) { @@ -241,62 +247,63 @@ return engine.processBlock(block, 0, block.length); } - + /** * Checks if the argument is a correctly PKCS#1.5 encoded Plaintext * for encryption. - * + * * @param encoded The Plaintext. - * @param pLen Expected length of the plaintext. + * @param pLen Expected length of the plaintext. * @return Either 0, if the encoding is correct, or -1, if it is incorrect. */ - private static int checkPkcs1Encoding(byte[] encoded, int pLen) { - int correct = 0; - /* + private static int checkPkcs1Encoding(byte[] encoded, int pLen) + { + int correct = 0; + /* * Check if the first two bytes are 0 2 */ - correct |= (encoded[0] ^ 2); + correct |= (encoded[0] ^ 2); /* * Now the padding check, check for no 0 byte in the padding */ - int plen = encoded.length - ( - pLen /* Lenght of the PMS */ - + 1 /* Final 0-byte before PMS */ - ); - - for (int i = 1; i < plen; i++) { - int tmp = encoded[i]; - tmp |= tmp >> 1; - tmp |= tmp >> 2; - tmp |= tmp >> 4; - correct |= (tmp & 1) - 1; - } + int plen = encoded.length - ( + pLen /* Lenght of the PMS */ + + 1 /* Final 0-byte before PMS */ + ); + + for (int i = 1; i < plen; i++) + { + int tmp = encoded[i]; + tmp |= tmp >> 1; + tmp |= tmp >> 2; + tmp |= tmp >> 4; + correct |= (tmp & 1) - 1; + } /* * Make sure the padding ends with a 0 byte. */ - correct |= encoded[encoded.length - (pLen +1)]; + correct |= encoded[encoded.length - (pLen + 1)]; /* * Return 0 or 1, depending on the result. */ - correct |= correct >> 1; - correct |= correct >> 2; - correct |= correct >> 4; - return ~((correct & 1) - 1); - } - + correct |= correct >> 1; + correct |= correct >> 2; + correct |= correct >> 4; + return ~((correct & 1) - 1); + } + /** * Decode PKCS#1.5 encoding, and return a random value if the padding is not correct. - * - * @param in The encrypted block. + * + * @param in The encrypted block. * @param inOff Offset in the encrypted block. * @param inLen Length of the encrypted block. - * //@param pLen Length of the desired output. + * //@param pLen Length of the desired output. * @return The plaintext without padding, or a random value if the padding was incorrect. - * * @throws InvalidCipherTextException */ private byte[] decodeBlockOrRandom(byte[] in, int inOff, int inLen) @@ -308,7 +315,7 @@ } byte[] block = engine.processBlock(in, inOff, inLen); - byte[] random = null; + byte[] random; if (this.fallback == null) { random = new byte[this.pLen]; @@ -319,30 +326,12 @@ random = fallback; } - /* - * TODO: This is a potential dangerous side channel. However, you can - * fix this by changing the RSA engine in a way, that it will always - * return blocks of the same length and prepend them with 0 bytes if - * needed. - */ - if (block.length < getOutputBlockSize()) - { - throw new InvalidCipherTextException("block truncated"); - } - - /* - * TODO: Potential side channel. Fix it by making the engine always - * return blocks of the correct length. - */ - if (useStrictLength && block.length != engine.getOutputBlockSize()) - { - throw new InvalidCipherTextException("block incorrect size"); - } + byte[] data = (useStrictLength & (block.length != engine.getOutputBlockSize())) ? blockBuffer : block; /* * Check the padding. */ - int correct = PKCS1Encoding.checkPkcs1Encoding(block, this.pLen); + int correct = PKCS1Encoding.checkPkcs1Encoding(data, this.pLen); /* * Now, to a constant time constant memory copy of the decrypted value @@ -351,89 +340,106 @@ byte[] result = new byte[this.pLen]; for (int i = 0; i < this.pLen; i++) { - result[i] = (byte)((block[i + (block.length - pLen)] & (~correct)) | (random[i] & correct)); + result[i] = (byte)((data[i + (data.length - pLen)] & (~correct)) | (random[i] & correct)); } + Arrays.fill(data, (byte)0); + return result; } /** - * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format. + * @throws InvalidCipherTextException if the decrypted block is not in PKCS1 format. */ private byte[] decodeBlock( - byte[] in, - int inOff, - int inLen) + byte[] in, + int inOff, + int inLen) throws InvalidCipherTextException { /* * If the length of the expected plaintext is known, we use a constant-time decryption. * If the decryption fails, we return a random value. */ - if (this.pLen != -1) + if (this.pLen != -1) { - return this.decodeBlockOrRandom(in, inOff, inLen); - } - + return this.decodeBlockOrRandom(in, inOff, inLen); + } + byte[] block = engine.processBlock(in, inOff, inLen); + boolean incorrectLength = (useStrictLength & (block.length != engine.getOutputBlockSize())); + byte[] data; if (block.length < getOutputBlockSize()) { - throw new InvalidCipherTextException("block truncated"); + data = blockBuffer; + } + else + { + data = block; } - byte type = block[0]; + byte type = data[0]; + boolean badType; if (forPrivateKey) { - if (type != 2) - { - throw new InvalidCipherTextException("unknown block type"); - } + badType = (type != 2); } else { - if (type != 1) - { - throw new InvalidCipherTextException("unknown block type"); - } + badType = (type != 1); } - if (useStrictLength && block.length != engine.getOutputBlockSize()) - { - throw new InvalidCipherTextException("block incorrect size"); - } - // // find and extract the message block. // - int start; - - for (start = 1; start != block.length; start++) - { - byte pad = block[start]; - - if (pad == 0) - { - break; - } - if (type == 1 && pad != (byte)0xff) - { - throw new InvalidCipherTextException("block padding incorrect"); - } - } + int start = findStart(type, data); start++; // data should start at the next byte - if (start > block.length || start < HEADER_LENGTH) + if (badType | start < HEADER_LENGTH) + { + Arrays.fill(data, (byte)0); + throw new InvalidCipherTextException("block incorrect"); + } + + // if we get this far, it's likely to be a genuine encoding error + if (incorrectLength) { - throw new InvalidCipherTextException("no data in block"); + Arrays.fill(data, (byte)0); + throw new InvalidCipherTextException("block incorrect size"); } - byte[] result = new byte[block.length - start]; + byte[] result = new byte[data.length - start]; - System.arraycopy(block, start, result, 0, result.length); + System.arraycopy(data, start, result, 0, result.length); return result; } + + private int findStart(byte type, byte[] block) + throws InvalidCipherTextException + { + int start = -1; + boolean padErr = false; + + for (int i = 1; i != block.length; i++) + { + byte pad = block[i]; + + if (pad == 0 & start < 0) + { + start = i; + } + padErr |= (type == 1 & start < 0 & pad != (byte)0xff); + } + + if (padErr) + { + return -1; + } + + return start; + } } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java 2015-11-03 06:53:32.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java 2016-10-30 22:00:47.000000000 +0000 @@ -5,6 +5,7 @@ import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; /** @@ -415,6 +416,8 @@ private int C0, C1, C2, C3; private boolean forEncryption; + private byte[] s; + private static final int BLOCK_SIZE = 16; /** @@ -440,6 +443,14 @@ { WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption); this.forEncryption = forEncryption; + if (forEncryption) + { + s = Arrays.clone(S); + } + else + { + s = Arrays.clone(Si); + } return; } @@ -578,10 +589,10 @@ // the final round's table is a simple function of S so we don't use a whole other four tables for it - this.C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0]; - this.C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1]; - this.C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2]; - this.C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3]; + this.C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((s[(r2>>16)&255]&255)<<16) ^ (s[(r3>>24)&255]<<24) ^ KW[r][0]; + this.C1 = (s[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (s[(r0>>24)&255]<<24) ^ KW[r][1]; + this.C2 = (s[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2]; + this.C3 = (s[r3&255]&255) ^ ((s[(r0>>8)&255]&255)<<8) ^ ((s[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3]; } private void decryptBlock(int[][] KW) @@ -610,9 +621,9 @@ // the final round's table is a simple function of Si so we don't use a whole other four tables for it - this.C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0]; - this.C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1]; - this.C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2]; - this.C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3]; + this.C0 = (Si[r0&255]&255) ^ ((s[(r3>>8)&255]&255)<<8) ^ ((s[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0]; + this.C1 = (s[r1&255]&255) ^ ((s[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (s[(r2>>24)&255]<<24) ^ KW[0][1]; + this.C2 = (s[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (s[(r3>>24)&255]<<24) ^ KW[0][2]; + this.C3 = (Si[r3&255]&255) ^ ((s[(r2>>8)&255]&255)<<8) ^ ((s[(r1>>16)&255]&255)<<16) ^ (s[(r0>>24)&255]<<24) ^ KW[0][3]; } } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java 2015-11-03 06:53:32.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java 2016-11-12 00:26:34.000000000 +0000 @@ -26,9 +26,11 @@ * the contents of the first * * The slowest version uses no static tables at all and computes the values in each round + *

*

- * This file contains the fast version with 8Kbytes of static tables for round precomputation - * + * This file contains the fast version with 8Kbytes of static tables for round precomputation. + *

+ * @deprecated unfortunately this class is has a few side channel issues. In an environment where encryption/decryption may be closely observed it should not be used. */ public class AESFastEngine implements BlockCipher diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/ChaCha7539Engine.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/ChaCha7539Engine.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/ChaCha7539Engine.java 2016-01-14 17:37:48.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/ChaCha7539Engine.java 2016-08-31 00:48:59.000000000 +0000 @@ -17,7 +17,7 @@ public String getAlgorithmName() { - return "ChaCha" + rounds; + return "ChaCha7539-" + rounds; } protected int getNonceSize() diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java 2015-05-05 06:31:33.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java 2016-12-22 00:30:24.000000000 +0000 @@ -6,11 +6,11 @@ import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.Wrapper; -import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.util.Arrays; /** @@ -51,7 +51,7 @@ // // checksum digest // - Digest sha1 = new SHA1Digest(); + Digest sha1 = DigestFactory.createSHA1(); byte[] digest = new byte[20]; /** diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java 2015-11-13 00:55:16.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java 2016-10-29 03:07:28.000000000 +0000 @@ -67,8 +67,8 @@ /** - * set up for use in conjunction with a block cipher to handle the - * message. + * Set up for use in conjunction with a block cipher to handle the + * message.It is strongly recommended that the cipher is not in ECB mode. * * @param agree the key agreement used as the basis for the encryption * @param kdf the key derivation function used for byte generation @@ -269,8 +269,8 @@ int inLen) throws InvalidCipherTextException { - byte[] M = null, K = null, K1 = null, K2 = null; - int len; + byte[] M, K, K1, K2; + int len = 0; // Ensure that the length of the input is greater than the MAC in bytes if (inLen < V.length + mac.getMacSize()) @@ -278,6 +278,7 @@ throw new InvalidCipherTextException("Length of input must be greater than the MAC and V combined"); } + // note order is important: set up keys, do simple encryptions, check mac, do final encryption. if (cipher == null) { // Streaming mode. @@ -298,14 +299,13 @@ System.arraycopy(K, K1.length, K2, 0, K2.length); } + // process the message M = new byte[K1.length]; for (int i = 0; i != K1.length; i++) { M[i] = (byte)(in_enc[inOff + V.length + i] ^ K1[i]); } - - len = K1.length; } else { @@ -325,15 +325,15 @@ } else { - cipher.init(false, new KeyParameter(K1)); + cipher.init(false, new KeyParameter(K1)); } M = new byte[cipher.getOutputSize(inLen - V.length - mac.getMacSize())]; + + // do initial processing len = cipher.processBytes(in_enc, inOff + V.length, inLen - V.length - mac.getMacSize(), M, 0); - len += cipher.doFinal(M, len); } - // Convert the length of the encoding vector into a byte array. byte[] P2 = param.getEncodingV(); byte[] L2 = null; @@ -362,11 +362,19 @@ if (!Arrays.constantTimeAreEqual(T1, T2)) { - throw new InvalidCipherTextException("Invalid MAC."); + throw new InvalidCipherTextException("invalid MAC"); + } + + if (cipher == null) + { + return M; } + else + { + len += cipher.doFinal(M, len); - // Output the message. - return Arrays.copyOfRange(M, 0, len); + return Arrays.copyOfRange(M, 0, len); + } } @@ -400,6 +408,10 @@ { throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e); } + catch (IllegalArgumentException e) + { + throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e); + } int encLength = (inLen - bIn.available()); this.V = Arrays.copyOfRange(in, inOff, inOff + encLength); diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/RC2WrapEngine.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/RC2WrapEngine.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/RC2WrapEngine.java 2015-07-29 04:49:22.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/RC2WrapEngine.java 2016-12-22 00:30:25.000000000 +0000 @@ -6,10 +6,10 @@ import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.Wrapper; -import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.util.Arrays; /** @@ -43,7 +43,7 @@ // // checksum digest // - Digest sha1 = new SHA1Digest(); + Digest sha1 = DigestFactory.createSHA1(); byte[] digest = new byte[20]; /** diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/RFC5649WrapEngine.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/RFC5649WrapEngine.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/engines/RFC5649WrapEngine.java 2015-05-16 04:11:53.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/engines/RFC5649WrapEngine.java 2016-10-07 21:41:07.000000000 +0000 @@ -48,6 +48,7 @@ if (param instanceof KeyParameter) { this.param = (KeyParameter)param; + this.preIV = highOrderIV; } else if (param instanceof ParametersWithIV) { @@ -192,7 +193,6 @@ System.arraycopy(extractedAIV, 0, extractedHighOrderAIV, 0, extractedHighOrderAIV.length); System.arraycopy(extractedAIV, extractedHighOrderAIV.length, mliBytes, 0, mliBytes.length); int mli = Pack.bigEndianToInt(mliBytes, 0); - // Even if a check fails we still continue and check everything // else in order to avoid certain timing based side-channel attacks. boolean isValid = true; diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/examples/DESExample.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/examples/DESExample.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/examples/DESExample.java 2014-03-21 04:06:26.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/examples/DESExample.java 2016-08-31 21:04:21.000000000 +0000 @@ -271,7 +271,7 @@ } catch (IOException closing) { - + System.err.println("exception closing resources: " + closing.getMessage()); } } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java 2015-07-25 20:15:57.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java 2016-12-22 00:30:24.000000000 +0000 @@ -8,6 +8,7 @@ import org.bouncycastle.crypto.params.DSAParameterGenerationParameters; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAValidationParameters; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.BigIntegers; import org.bouncycastle.util.encoders.Hex; @@ -31,7 +32,7 @@ public DSAParametersGenerator() { - this(new SHA1Digest()); + this(DigestFactory.createSHA1()); } public DSAParametersGenerator(Digest digest) diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java 2013-07-26 05:06:42.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java 2016-12-22 00:30:25.000000000 +0000 @@ -3,9 +3,9 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.PBEParametersGenerator; -import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.crypto.util.DigestFactory; /** * Generator for PBE derived keys and ivs as usd by OpenSSL. @@ -17,7 +17,7 @@ public class OpenSSLPBEParametersGenerator extends PBEParametersGenerator { - private Digest digest = new MD5Digest(); + private Digest digest = DigestFactory.createMD5(); /** * Construct a OpenSSL Parameters generator. diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java 2015-04-20 06:28:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java 2016-12-22 00:30:24.000000000 +0000 @@ -4,10 +4,10 @@ import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.Mac; import org.bouncycastle.crypto.PBEParametersGenerator; -import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.util.Arrays; /** @@ -29,7 +29,7 @@ */ public PKCS5S2ParametersGenerator() { - this(new SHA1Digest()); + this(DigestFactory.createSHA1()); } public PKCS5S2ParametersGenerator(Digest digest) diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java 2015-02-20 19:51:29.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java 2016-11-11 22:28:45.000000000 +0000 @@ -56,9 +56,9 @@ * * @param kdf the key derivation function to be used. * @param rnd the random source for the session key. - * @param cofactorMode true to use the new cofactor ECDH. - * @param oldCofactorMode true to use the old cofactor ECDH. - * @param singleHashMode true to use single hash mode. + * @param cofactorMode if true use the new cofactor ECDH. + * @param oldCofactorMode if true use the old cofactor ECDH. + * @param singleHashMode if true use single hash mode. */ public ECIESKeyEncapsulation( DerivationFunction kdf, @@ -228,7 +228,7 @@ protected KeyParameter deriveKey(int keyLen, byte[] C, byte[] PEH) { byte[] kdfInput = PEH; - if (SingleHashMode) + if (!SingleHashMode) { kdfInput = Arrays.concatenate(C, PEH); Arrays.fill(PEH, (byte)0); diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java 2016-01-14 17:36:39.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java 2016-12-08 08:38:51.000000000 +0000 @@ -33,6 +33,7 @@ // These fields are set by init and not modified by processing private boolean forEncryption; private int macSize; + private byte[] lastKey; private byte[] nonce; private byte[] initialAssociatedText; private byte[] H; @@ -95,12 +96,13 @@ this.macBlock = null; KeyParameter keyParam; + byte[] newNonce = null; if (params instanceof AEADParameters) { AEADParameters param = (AEADParameters)params; - nonce = param.getNonce(); + newNonce = param.getNonce(); initialAssociatedText = param.getAssociatedText(); int macSizeBits = param.getMacSize(); @@ -116,7 +118,7 @@ { ParametersWithIV param = (ParametersWithIV)params; - nonce = param.getIV(); + newNonce = param.getIV(); initialAssociatedText = null; macSize = 16; keyParam = (KeyParameter)param.getParameters(); @@ -129,11 +131,32 @@ int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize); this.bufBlock = new byte[bufLength]; - if (nonce == null || nonce.length < 1) + if (newNonce == null || newNonce.length < 1) { throw new IllegalArgumentException("IV must be at least 1 byte"); } + if (forEncryption) + { + if (nonce != null && Arrays.areEqual(nonce, newNonce)) + { + if (keyParam == null) + { + throw new IllegalArgumentException("cannot reuse nonce for GCM encryption"); + } + if (lastKey != null && Arrays.areEqual(lastKey, keyParam.getKey())) + { + throw new IllegalArgumentException("cannot reuse nonce for GCM encryption"); + } + } + } + + nonce = newNonce; + if (keyParam != null) + { + lastKey = keyParam.getKey(); + } + // TODO Restrict macSize to 16 if nonce length not 12? // Cipher always used in forward mode @@ -189,6 +212,10 @@ public byte[] getMac() { + if (macBlock == null) + { + return new byte[macSize]; + } return Arrays.clone(macBlock); } @@ -450,6 +477,8 @@ { cipher.reset(); + // note: we do not reset the nonce. + S = new byte[BLOCK_SIZE]; S_at = new byte[BLOCK_SIZE]; S_atPre = new byte[BLOCK_SIZE]; diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java 2014-07-09 23:52:49.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java 2016-12-08 08:41:00.000000000 +0000 @@ -254,6 +254,10 @@ public byte[] getMac() { + if (macBlock == null) + { + return new byte[macSize]; + } return Arrays.clone(macBlock); } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java 2013-07-26 05:06:42.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java 2016-10-31 22:48:02.000000000 +0000 @@ -5,6 +5,9 @@ public class DHPublicKeyParameters extends DHKeyParameters { + private static final BigInteger ONE = BigInteger.valueOf(1); + private static final BigInteger TWO = BigInteger.valueOf(2); + private BigInteger y; public DHPublicKeyParameters( @@ -13,9 +16,37 @@ { super(false, params); - this.y = y; + this.y = validate(y, params); } + private BigInteger validate(BigInteger y, DHParameters dhParams) + { + if (y == null) + { + throw new NullPointerException("y value cannot be null"); + } + + // TLS check + if (y.compareTo(TWO) < 0 || y.compareTo(dhParams.getP().subtract(TWO)) > 0) + { + throw new IllegalArgumentException("invalid DH public key"); + } + + if (dhParams.getQ() != null) + { + if (ONE.equals(y.modPow(dhParams.getQ(), dhParams.getP()))) + { + return y; + } + + throw new IllegalArgumentException("Y value does not appear to be in correct group"); + } + else + { + return y; // we can't validate without Q. + } + } + public BigInteger getY() { return y; diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java 2013-07-26 05:06:41.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java 2016-08-21 03:39:20.000000000 +0000 @@ -5,6 +5,9 @@ public class DSAPublicKeyParameters extends DSAKeyParameters { + private static final BigInteger ONE = BigInteger.valueOf(1); + private static final BigInteger TWO = BigInteger.valueOf(2); + private BigInteger y; public DSAPublicKeyParameters( @@ -13,9 +16,27 @@ { super(false, params); - this.y = y; + this.y = validate(y, params); } + private BigInteger validate(BigInteger y, DSAParameters params) + { + if (params != null) + { + if (TWO.compareTo(y) <= 0 && params.getP().subtract(TWO).compareTo(y) >= 0 + && ONE.equals(y.modPow(params.getQ(), params.getP()))) + { + return y; + } + + throw new IllegalArgumentException("y value does not appear to be in correct group"); + } + else + { + return y; // we can't validate without params, fortunately we can't use the key either... + } + } + public BigInteger getY() { return y; diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java 2015-10-14 03:30:04.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java 2016-08-21 01:56:47.000000000 +0000 @@ -5,14 +5,37 @@ public class ECPublicKeyParameters extends ECKeyParameters { - ECPoint Q; + private final ECPoint Q; public ECPublicKeyParameters( ECPoint Q, ECDomainParameters params) { super(false, params); - this.Q = Q.normalize(); + + this.Q = validate(Q); + } + + private ECPoint validate(ECPoint q) + { + if (q == null) + { + throw new IllegalArgumentException("point has null value"); + } + + if (q.isInfinity()) + { + throw new IllegalArgumentException("point at infinity"); + } + + q = q.normalize(); + + if (!q.isValid()) + { + throw new IllegalArgumentException("point not on curve"); + } + + return q; } public ECPoint getQ() diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java 2013-07-26 05:06:41.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java 2016-12-20 01:53:07.000000000 +0000 @@ -5,6 +5,8 @@ public class RSAKeyParameters extends AsymmetricKeyParameter { + private static final BigInteger ONE = BigInteger.valueOf(1); + private BigInteger modulus; private BigInteger exponent; @@ -15,10 +17,40 @@ { super(isPrivate); - this.modulus = modulus; + if (!isPrivate) + { + if ((exponent.intValue() & 1) == 0) + { + throw new IllegalArgumentException("RSA publicExponent is even"); + } + } + + this.modulus = validate(modulus); this.exponent = exponent; } + private BigInteger validate(BigInteger modulus) + { + if ((modulus.intValue() & 1) == 0) + { + throw new IllegalArgumentException("RSA modulus is even"); + } + + // the value is the product of the 132 smallest primes from 3 to 751 + if (!modulus.gcd(new BigInteger("145188775577763990151158743208307020242261438098488931355057091965" + + "931517706595657435907891265414916764399268423699130577757433083166" + + "651158914570105971074227669275788291575622090199821297575654322355" + + "049043101306108213104080801056529374892690144291505781966373045481" + + "8359472391642885328171302299245556663073719855")).equals(ONE)) + { + throw new IllegalArgumentException("RSA modulus has a small prime factor"); + } + + // TODO: add additional primePower/Composite test - expensive!! + + return modulus; + } + public BigInteger getModulus() { return modulus; diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java 2014-08-27 01:47:04.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java 2016-10-15 02:33:39.000000000 +0000 @@ -95,7 +95,8 @@ BigInteger k = kCalculator.nextK(); - BigInteger r = params.getG().modPow(k, params.getP()).mod(q); + // the randomizer is to conceal timing information related to k and x. + BigInteger r = params.getG().modPow(k.add(getRandomizer(q, random)), params.getP()).mod(q); k = k.modInverse(q).multiply(m.add(x.multiply(r))); @@ -163,4 +164,12 @@ { return !needed ? null : (provided != null) ? provided : new SecureRandom(); } + + private BigInteger getRandomizer(BigInteger q, SecureRandom provided) + { + // Calculate a random multiple of q to add to k. Note that g^q = 1 (mod p), so adding multiple of q to k does not change r. + int randomBits = 7; + + return new BigInteger(randomBits, provided != null ? provided : new SecureRandom()).add(BigInteger.valueOf(128)).multiply(q); + } } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/DatagramTransport.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/DatagramTransport.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/DatagramTransport.java 2013-12-16 20:11:31.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/DatagramTransport.java 2016-11-22 03:28:11.000000000 +0000 @@ -2,6 +2,9 @@ import java.io.IOException; +/** + * Base interface for an object sending and receiving DTLS data. + */ public interface DatagramTransport { int getReceiveLimit() diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsServer.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsServer.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsServer.java 2016-03-01 16:11:07.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsServer.java 2016-10-25 05:58:45.000000000 +0000 @@ -44,7 +44,7 @@ protected DHParameters getDHParameters() { - return DHStandardGroups.rfc5114_2048_256; + return DHStandardGroups.rfc3526_2048; } protected int[] getCipherSuites() diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java 2016-01-18 05:39:21.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java 2016-11-11 19:24:50.000000000 +0000 @@ -61,19 +61,29 @@ } catch (TlsFatalAlert fatalAlert) { - recordLayer.fail(fatalAlert.getAlertDescription()); + abortClientHandshake(state, recordLayer, fatalAlert.getAlertDescription()); throw fatalAlert; } catch (IOException e) { - recordLayer.fail(AlertDescription.internal_error); + abortClientHandshake(state, recordLayer, AlertDescription.internal_error); throw e; } catch (RuntimeException e) { - recordLayer.fail(AlertDescription.internal_error); + abortClientHandshake(state, recordLayer, AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } + finally + { + securityParameters.clear(); + } + } + + protected void abortClientHandshake(ClientHandshakeState state, DTLSRecordLayer recordLayer, short alertDescription) + { + recordLayer.fail(alertDescription); + invalidateSession(state); } protected DTLSTransport clientHandshake(ClientHandshakeState state, DTLSRecordLayer recordLayer) diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java 2015-12-21 19:58:08.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java 2016-11-11 19:24:50.000000000 +0000 @@ -243,7 +243,7 @@ if (alertLevel == AlertLevel.fatal) { - fail(alertDescription); + failed(); throw new TlsFatalAlert(alertDescription); } @@ -398,6 +398,16 @@ failed = true; closeTransport(); + } + } + + void failed() + { + if (!closed) + { + failed = true; + + closeTransport(); } } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java 2016-02-07 01:27:38.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java 2016-11-11 19:24:50.000000000 +0000 @@ -66,19 +66,29 @@ } catch (TlsFatalAlert fatalAlert) { - recordLayer.fail(fatalAlert.getAlertDescription()); + abortServerHandshake(state, recordLayer, fatalAlert.getAlertDescription()); throw fatalAlert; } catch (IOException e) { - recordLayer.fail(AlertDescription.internal_error); + abortServerHandshake(state, recordLayer, AlertDescription.internal_error); throw e; } catch (RuntimeException e) { - recordLayer.fail(AlertDescription.internal_error); + abortServerHandshake(state, recordLayer, AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } + finally + { + securityParameters.clear(); + } + } + + protected void abortServerHandshake(ServerHandshakeState state, DTLSRecordLayer recordLayer, short alertDescription) + { + recordLayer.fail(alertDescription); + invalidateSession(state); } protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLayer recordLayer) @@ -432,6 +442,21 @@ return buf.toByteArray(); } + protected void invalidateSession(ServerHandshakeState state) + { + if (state.sessionParameters != null) + { + state.sessionParameters.clear(); + state.sessionParameters = null; + } + + if (state.tlsSession != null) + { + state.tlsSession.invalidate(); + state.tlsSession = null; + } + } + protected void notifyClientCertificate(ServerHandshakeState state, Certificate clientCertificate) throws IOException { @@ -694,6 +719,9 @@ { TlsServer server = null; TlsServerContextImpl serverContext = null; + TlsSession tlsSession = null; + SessionParameters sessionParameters = null; + SessionParameters.Builder sessionParametersBuilder = null; int[] offeredCipherSuites = null; short[] offeredCompressionMethods = null; Hashtable clientExtensions = null; diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/PSKTlsServer.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/PSKTlsServer.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/PSKTlsServer.java 2015-05-26 04:22:56.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/PSKTlsServer.java 2016-10-25 05:58:45.000000000 +0000 @@ -28,7 +28,7 @@ protected DHParameters getDHParameters() { - return DHStandardGroups.rfc5114_2048_256; + return DHStandardGroups.rfc3526_2048; } protected int[] getCipherSuites() diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsAuthentication.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsAuthentication.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsAuthentication.java 2013-07-26 05:06:42.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsAuthentication.java 2016-11-22 03:29:19.000000000 +0000 @@ -2,6 +2,9 @@ import java.io.IOException; +/** + * Base interface to provide TLS authentication credentials. + */ public interface TlsAuthentication { /** diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsClientContext.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsClientContext.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsClientContext.java 2013-07-26 05:06:42.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsClientContext.java 2016-11-22 03:31:26.000000000 +0000 @@ -1,5 +1,8 @@ package org.bouncycastle.crypto.tls; +/** + * Marker interface to distinguish a TLS client context. + */ public interface TlsClientContext extends TlsContext { diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsClient.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsClient.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsClient.java 2015-12-19 20:27:13.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsClient.java 2016-11-22 03:30:28.000000000 +0000 @@ -4,6 +4,9 @@ import java.util.Hashtable; import java.util.Vector; +/** + * Interface describing a TLS client endpoint. + */ public interface TlsClient extends TlsPeer { diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsServerContext.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsServerContext.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsServerContext.java 2013-07-26 05:06:42.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsServerContext.java 2016-11-22 03:31:26.000000000 +0000 @@ -1,5 +1,8 @@ package org.bouncycastle.crypto.tls; +/** + * Marker interface to distinguish a TLS server context. + */ public interface TlsServerContext extends TlsContext { diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsServer.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsServer.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsServer.java 2014-10-17 06:57:58.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsServer.java 2016-11-22 03:30:28.000000000 +0000 @@ -4,6 +4,9 @@ import java.util.Hashtable; import java.util.Vector; +/** + * Interface describing a TLS server endpoint. + */ public interface TlsServer extends TlsPeer { diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java 2016-03-01 16:11:07.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java 2016-12-22 02:11:44.000000000 +0000 @@ -1433,6 +1433,7 @@ case EncryptionAlgorithm.SEED_CBC: return CipherType.block; + case EncryptionAlgorithm.NULL: case EncryptionAlgorithm.RC4_40: case EncryptionAlgorithm.RC4_128: return CipherType.stream; diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java 2016-12-22 00:30:24.000000000 +0000 @@ -0,0 +1,77 @@ +package org.bouncycastle.crypto.util; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.MD5Digest; +import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.digests.SHA224Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA3Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.digests.SHA512tDigest; + +/** + * Basic factory class for message digests. + */ +public final class DigestFactory +{ + public static Digest createMD5() + { + return new MD5Digest(); + } + + public static Digest createSHA1() + { + return new SHA1Digest(); + } + + public static Digest createSHA224() + { + return new SHA224Digest(); + } + + public static Digest createSHA256() + { + return new SHA256Digest(); + } + + public static Digest createSHA384() + { + return new SHA384Digest(); + } + + public static Digest createSHA512() + { + return new SHA512Digest(); + } + + public static Digest createSHA512_224() + { + return new SHA512tDigest(224); + } + + public static Digest createSHA512_256() + { + return new SHA512tDigest(256); + } + + public static Digest createSHA3_224() + { + return new SHA3Digest(224); + } + + public static Digest createSHA3_256() + { + return new SHA3Digest(256); + } + + public static Digest createSHA3_384() + { + return new SHA3Digest(384); + } + + public static Digest createSHA3_512() + { + return new SHA3Digest(512); + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java 2015-11-14 02:33:24.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java 2016-08-20 23:40:50.000000000 +0000 @@ -28,10 +28,15 @@ */ public class PrivateKeyInfoFactory { + private PrivateKeyInfoFactory() + { + + } + /** * Create a PrivateKeyInfo representation of a private key. * - * @param privateKey the SubjectPublicKeyInfo encoding + * @param privateKey the key to be encoded into the info object. * @return the appropriate key parameter * @throws java.io.IOException on an error encoding the key */ diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java 2015-06-25 08:04:01.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java 2016-08-20 23:40:50.000000000 +0000 @@ -28,11 +28,16 @@ */ public class SubjectPublicKeyInfoFactory { + private SubjectPublicKeyInfoFactory() + { + + } + /** * Create a SubjectPublicKeyInfo public key. * - * @param publicKey the SubjectPublicKeyInfo encoding - * @return the appropriate key parameter + * @param publicKey the key to be encoded into the info object. + * @return a SubjectPublicKeyInfo representing the key. * @throws java.io.IOException on an error encoding the key */ public static SubjectPublicKeyInfo createSubjectPublicKeyInfo(AsymmetricKeyParameter publicKey) throws IOException diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/LICENSE.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/LICENSE.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/LICENSE.java 2016-08-18 04:36:09.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/LICENSE.java 2016-08-18 06:13:08.000000000 +0000 @@ -5,7 +5,7 @@ /** * The Bouncy Castle License * - * Copyright (c) 2000-2015 The Legion Of The Bouncy Castle Inc. (http://www.bouncycastle.org) + * Copyright (c) 2000-2016 The Legion Of The Bouncy Castle Inc. (http://www.bouncycastle.org) *

* Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without restriction, @@ -26,7 +26,7 @@ public class LICENSE { public static String licenseText = - "Copyright (c) 2000-2015 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) " + "Copyright (c) 2000-2016 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) " + Strings.lineSeparator() + Strings.lineSeparator() + "Permission is hereby granted, free of charge, to any person obtaining a copy of this software " diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java 2015-02-10 00:37:10.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java 2016-11-10 09:53:44.000000000 +0000 @@ -440,7 +440,7 @@ * 1) additions do not use the curve's A, B coefficients. * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ... */ - if (ECAlgorithms.isFpCurve(c) && c.getFieldSize() >= 64) + if (!twiceP.isInfinity() && ECAlgorithms.isFpCurve(c) && c.getFieldSize() >= 64) { switch (c.getCoordinateSystem()) { diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/raw/Nat128.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/raw/Nat128.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/raw/Nat128.java 2015-03-24 08:43:38.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/raw/Nat128.java 2016-11-29 03:01:29.000000000 +0000 @@ -636,8 +636,8 @@ } long x_3 = x[3] & M; - long zz_5 = zz[5] & M; - long zz_6 = zz[6] & M; + long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -658,7 +658,7 @@ w = (int)zz_6; zz[6] = (w << 1) | c; c = w >>> 31; - w = zz[7] + (int)(zz_6 >> 32); + w = zz[7] + (int)(zz_6 >>> 32); zz[7] = (w << 1) | c; } @@ -713,8 +713,8 @@ } long x_3 = x[xOff + 3] & M; - long zz_5 = zz[zzOff + 5] & M; - long zz_6 = zz[zzOff + 6] & M; + long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -734,7 +734,7 @@ w = (int)zz_6; zz[zzOff + 6] = (w << 1) | c; c = w >>> 31; - w = zz[zzOff + 7] + (int)(zz_6 >> 32); + w = zz[zzOff + 7] + (int)(zz_6 >>> 32); zz[zzOff + 7] = (w << 1) | c; } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/raw/Nat160.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/raw/Nat160.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/raw/Nat160.java 2015-03-24 08:43:38.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/raw/Nat160.java 2016-11-29 03:01:29.000000000 +0000 @@ -609,8 +609,8 @@ } long x_3 = x[3] & M; - long zz_5 = zz[5] & M; - long zz_6 = zz[6] & M; + long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -624,8 +624,8 @@ } long x_4 = x[4] & M; - long zz_7 = zz[7] & M; - long zz_8 = zz[8] & M; + long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -649,7 +649,7 @@ w = (int)zz_8; zz[8] = (w << 1) | c; c = w >>> 31; - w = zz[9] + (int)(zz_8 >> 32); + w = zz[9] + (int)(zz_8 >>> 32); zz[9] = (w << 1) | c; } @@ -704,8 +704,8 @@ } long x_3 = x[xOff + 3] & M; - long zz_5 = zz[zzOff + 5] & M; - long zz_6 = zz[zzOff + 6] & M; + long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -719,8 +719,8 @@ } long x_4 = x[xOff + 4] & M; - long zz_7 = zz[zzOff + 7] & M; - long zz_8 = zz[zzOff + 8] & M; + long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -744,7 +744,7 @@ w = (int)zz_8; zz[zzOff + 8] = (w << 1) | c; c = w >>> 31; - w = zz[zzOff + 9] + (int)(zz_8 >> 32); + w = zz[zzOff + 9] + (int)(zz_8 >>> 32); zz[zzOff + 9] = (w << 1) | c; } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/raw/Nat192.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/raw/Nat192.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/raw/Nat192.java 2015-03-24 08:43:38.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/raw/Nat192.java 2016-11-29 03:01:29.000000000 +0000 @@ -715,8 +715,8 @@ } long x_3 = x[3] & M; - long zz_5 = zz[5] & M; - long zz_6 = zz[6] & M; + long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -730,8 +730,8 @@ } long x_4 = x[4] & M; - long zz_7 = zz[7] & M; - long zz_8 = zz[8] & M; + long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -747,8 +747,8 @@ } long x_5 = x[5] & M; - long zz_9 = zz[9] & M; - long zz_10 = zz[10] & M; + long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -776,7 +776,7 @@ w = (int)zz_10; zz[10] = (w << 1) | c; c = w >>> 31; - w = zz[11] + (int)(zz_10 >> 32); + w = zz[11] + (int)(zz_10 >>> 32); zz[11] = (w << 1) | c; } @@ -831,8 +831,8 @@ } long x_3 = x[xOff + 3] & M; - long zz_5 = zz[zzOff + 5] & M; - long zz_6 = zz[zzOff + 6] & M; + long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -846,8 +846,8 @@ } long x_4 = x[xOff + 4] & M; - long zz_7 = zz[zzOff + 7] & M; - long zz_8 = zz[zzOff + 8] & M; + long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -863,8 +863,8 @@ } long x_5 = x[xOff + 5] & M; - long zz_9 = zz[zzOff + 9] & M; - long zz_10 = zz[zzOff + 10] & M; + long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -892,7 +892,7 @@ w = (int)zz_10; zz[zzOff + 10] = (w << 1) | c; c = w >>> 31; - w = zz[zzOff + 11] + (int)(zz_10 >> 32); + w = zz[zzOff + 11] + (int)(zz_10 >>> 32); zz[zzOff + 11] = (w << 1) | c; } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/raw/Nat224.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/raw/Nat224.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/raw/Nat224.java 2014-06-21 02:53:15.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/raw/Nat224.java 2016-11-29 03:01:29.000000000 +0000 @@ -793,8 +793,8 @@ } long x_3 = x[3] & M; - long zz_5 = zz[5] & M; - long zz_6 = zz[6] & M; + long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -808,8 +808,8 @@ } long x_4 = x[4] & M; - long zz_7 = zz[7] & M; - long zz_8 = zz[8] & M; + long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -825,8 +825,8 @@ } long x_5 = x[5] & M; - long zz_9 = zz[9] & M; - long zz_10 = zz[10] & M; + long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -844,8 +844,8 @@ } long x_6 = x[6] & M; - long zz_11 = zz[11] & M; - long zz_12 = zz[12] & M; + long zz_11 = (zz[11] & M) + (zz_10 >>> 32); zz_10 &= M; + long zz_12 = (zz[12] & M) + (zz_11 >>> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (int)zz_6; @@ -877,7 +877,7 @@ w = (int)zz_12; zz[12] = (w << 1) | c; c = w >>> 31; - w = zz[13] + (int)(zz_12 >> 32); + w = zz[13] + (int)(zz_12 >>> 32); zz[13] = (w << 1) | c; } @@ -932,8 +932,8 @@ } long x_3 = x[xOff + 3] & M; - long zz_5 = zz[zzOff + 5] & M; - long zz_6 = zz[zzOff + 6] & M; + long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -947,8 +947,8 @@ } long x_4 = x[xOff + 4] & M; - long zz_7 = zz[zzOff + 7] & M; - long zz_8 = zz[zzOff + 8] & M; + long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -964,8 +964,8 @@ } long x_5 = x[xOff + 5] & M; - long zz_9 = zz[zzOff + 9] & M; - long zz_10 = zz[zzOff + 10] & M; + long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -983,8 +983,8 @@ } long x_6 = x[xOff + 6] & M; - long zz_11 = zz[zzOff + 11] & M; - long zz_12 = zz[zzOff + 12] & M; + long zz_11 = (zz[zzOff + 11] & M) + (zz_10 >>> 32); zz_10 &= M; + long zz_12 = (zz[zzOff + 12] & M) + (zz_11 >>> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (int)zz_6; @@ -1016,7 +1016,7 @@ w = (int)zz_12; zz[zzOff + 12] = (w << 1) | c; c = w >>> 31; - w = zz[zzOff + 13] + (int)(zz_12 >> 32); + w = zz[zzOff + 13] + (int)(zz_12 >>> 32); zz[zzOff + 13] = (w << 1) | c; } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/raw/Nat256.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/raw/Nat256.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/math/raw/Nat256.java 2015-03-24 08:43:38.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/math/raw/Nat256.java 2016-11-29 03:01:29.000000000 +0000 @@ -926,8 +926,8 @@ } long x_3 = x[3] & M; - long zz_5 = zz[5] & M; - long zz_6 = zz[6] & M; + long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -941,8 +941,8 @@ } long x_4 = x[4] & M; - long zz_7 = zz[7] & M; - long zz_8 = zz[8] & M; + long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -958,8 +958,8 @@ } long x_5 = x[5] & M; - long zz_9 = zz[9] & M; - long zz_10 = zz[10] & M; + long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -977,8 +977,8 @@ } long x_6 = x[6] & M; - long zz_11 = zz[11] & M; - long zz_12 = zz[12] & M; + long zz_11 = (zz[11] & M) + (zz_10 >>> 32); zz_10 &= M; + long zz_12 = (zz[12] & M) + (zz_11 >>> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (int)zz_6; @@ -998,8 +998,8 @@ } long x_7 = x[7] & M; - long zz_13 = zz[13] & M; - long zz_14 = zz[14] & M; + long zz_13 = (zz[13] & M) + (zz_12 >>> 32); zz_12 &= M; + long zz_14 = (zz[14] & M) + (zz_13 >>> 32); zz_13 &= M; { zz_7 += x_7 * x_0; w = (int)zz_7; @@ -1035,7 +1035,7 @@ w = (int)zz_14; zz[14] = (w << 1) | c; c = w >>> 31; - w = zz[15] + (int)(zz_14 >> 32); + w = zz[15] + (int)(zz_14 >>> 32); zz[15] = (w << 1) | c; } @@ -1090,8 +1090,8 @@ } long x_3 = x[xOff + 3] & M; - long zz_5 = zz[zzOff + 5] & M; - long zz_6 = zz[zzOff + 6] & M; + long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -1105,8 +1105,8 @@ } long x_4 = x[xOff + 4] & M; - long zz_7 = zz[zzOff + 7] & M; - long zz_8 = zz[zzOff + 8] & M; + long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -1122,8 +1122,8 @@ } long x_5 = x[xOff + 5] & M; - long zz_9 = zz[zzOff + 9] & M; - long zz_10 = zz[zzOff + 10] & M; + long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -1141,8 +1141,8 @@ } long x_6 = x[xOff + 6] & M; - long zz_11 = zz[zzOff + 11] & M; - long zz_12 = zz[zzOff + 12] & M; + long zz_11 = (zz[zzOff + 11] & M) + (zz_10 >>> 32); zz_10 &= M; + long zz_12 = (zz[zzOff + 12] & M) + (zz_11 >>> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (int)zz_6; @@ -1162,8 +1162,8 @@ } long x_7 = x[xOff + 7] & M; - long zz_13 = zz[zzOff + 13] & M; - long zz_14 = zz[zzOff + 14] & M; + long zz_13 = (zz[zzOff + 13] & M) + (zz_12 >>> 32); zz_12 &= M; + long zz_14 = (zz[zzOff + 14] & M) + (zz_13 >>> 32); zz_13 &= M; { zz_7 += x_7 * x_0; w = (int)zz_7; @@ -1199,7 +1199,7 @@ w = (int)zz_14; zz[zzOff + 14] = (w << 1) | c; c = w >>> 31; - w = zz[zzOff + 15] + (int)(zz_14 >> 32); + w = zz[zzOff + 15] + (int)(zz_14 >>> 32); zz[zzOff + 15] = (w << 1) | c; } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/util/Arrays.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/util/Arrays.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/util/Arrays.java 2016-06-28 03:31:48.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/util/Arrays.java 2016-09-29 23:45:47.000000000 +0000 @@ -262,6 +262,44 @@ return true; } + public static int compareUnsigned(byte[] a, byte[] b) + { + if (a == b) + { + return 0; + } + if (a == null) + { + return -1; + } + if (b == null) + { + return 1; + } + int minLen = Math.min(a.length, b.length); + for (int i = 0; i < minLen; ++i) + { + int aVal = a[i] & 0xFF, bVal = b[i] & 0xFF; + if (aVal < bVal) + { + return -1; + } + if (aVal > bVal) + { + return 1; + } + } + if (a.length < b.length) + { + return -1; + } + if (a.length > b.length) + { + return 1; + } + return 0; + } + public static boolean contains(short[] a, short n) { for (int i = 0; i < a.length; ++i) diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/util/test/FixedSecureRandom.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/util/test/FixedSecureRandom.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/util/test/FixedSecureRandom.java 2013-07-26 05:06:42.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/util/test/FixedSecureRandom.java 2016-09-28 20:11:11.000000000 +0000 @@ -2,75 +2,230 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.security.Provider; import java.security.SecureRandom; +import org.bouncycastle.util.Pack; +import org.bouncycastle.util.encoders.Hex; + +/** + * A secure random that returns pre-seeded data to calls of nextBytes() or generateSeed(). + */ public class FixedSecureRandom extends SecureRandom { - private byte[] _data; - - private int _index; - private int _intPad; - - public FixedSecureRandom(byte[] value) + private static java.math.BigInteger REGULAR = new java.math.BigInteger("01020304ffffffff0506070811111111", 16); + private static java.math.BigInteger ANDROID = new java.math.BigInteger("1111111105060708ffffffff01020304", 16); + private static java.math.BigInteger CLASSPATH = new java.math.BigInteger("3020104ffffffff05060708111111", 16); + + private static final boolean isAndroidStyle; + private static final boolean isClasspathStyle; + private static final boolean isRegularStyle; + + static { - this(false, new byte[][] { value }); + java.math.BigInteger check1 = new java.math.BigInteger(128, new RandomChecker()); + java.math.BigInteger check2 = new java.math.BigInteger(120, new RandomChecker()); + + isAndroidStyle = check1.equals(ANDROID); + isRegularStyle = check1.equals(REGULAR); + isClasspathStyle = check2.equals(CLASSPATH); } - - public FixedSecureRandom( - byte[][] values) + + private byte[] _data; + private int _index; + + /** + * Base class for sources of fixed "Randomness" + */ + public static class Source { - this(false, values); + byte[] data; + + Source(byte[] data) + { + this.data = data; + } } - + /** - * Pad the data on integer boundaries. This is necessary for the classpath project's BigInteger - * implementation. + * Data Source - in this case we just expect requests for byte arrays. */ - public FixedSecureRandom( - boolean intPad, - byte[] value) + public static class Data + extends Source { - this(intPad, new byte[][] { value }); + public Data(byte[] data) + { + super(data); + } } - + /** - * Pad the data on integer boundaries. This is necessary for the classpath project's BigInteger - * implementation. + * BigInteger Source - in this case we expect requests for data that will be used + * for BigIntegers. The FixedSecureRandom will attempt to compensate for platform differences here. */ + public static class BigInteger + extends Source + { + public BigInteger(byte[] data) + { + super(data); + } + + public BigInteger(int bitLength, byte[] data) + { + super(expandToBitLength(bitLength, data)); + } + + public BigInteger(String hexData) + { + this(Hex.decode(hexData)); + } + + public BigInteger(int bitLength, String hexData) + { + super(expandToBitLength(bitLength, Hex.decode(hexData))); + } + } + + public FixedSecureRandom(byte[] value) + { + this(new Source[] { new Data(value) }); + } + public FixedSecureRandom( - boolean intPad, byte[][] values) { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - + this(buildDataArray(values)); + } + + private static Data[] buildDataArray(byte[][] values) + { + Data[] res = new Data[values.length]; + for (int i = 0; i != values.length; i++) { - try + res[i] = new Data(values[i]); + } + + return res; + } + + public FixedSecureRandom( + Source[] sources) + { + super(null, new DummyProvider()); // to prevent recursion in provider creation + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + if (isRegularStyle) + { + if (isClasspathStyle) { - bOut.write(values[i]); + for (int i = 0; i != sources.length; i++) + { + try + { + if (sources[i] instanceof BigInteger) + { + byte[] data = sources[i].data; + int len = data.length - (data.length % 4); + for (int w = data.length - len - 1; w >= 0; w--) + { + bOut.write(data[w]); + } + for (int w = data.length - len; w < data.length; w += 4) + { + bOut.write(data, w, 4); + } + } + else + { + bOut.write(sources[i].data); + } + } + catch (IOException e) + { + throw new IllegalArgumentException("can't save value source."); + } + } } - catch (IOException e) + else { - throw new IllegalArgumentException("can't save value array."); + for (int i = 0; i != sources.length; i++) + { + try + { + bOut.write(sources[i].data); + } + catch (IOException e) + { + throw new IllegalArgumentException("can't save value source."); + } + } } } - - _data = bOut.toByteArray(); - - if (intPad) + else if (isAndroidStyle) + { + for (int i = 0; i != sources.length; i++) + { + try + { + if (sources[i] instanceof BigInteger) + { + byte[] data = sources[i].data; + int len = data.length - (data.length % 4); + for (int w = 0; w < len; w += 4) + { + bOut.write(data, data.length - (w + 4), 4); + } + if (data.length - len != 0) + { + for (int w = 0; w != 4 - (data.length - len); w++) + { + bOut.write(0); + } + } + for (int w = 0; w != data.length - len; w++) + { + bOut.write(data[len + w]); + } + } + else + { + bOut.write(sources[i].data); + } + } + catch (IOException e) + { + throw new IllegalArgumentException("can't save value source."); + } + } + } + else { - _intPad = _data.length % 4; + throw new IllegalStateException("Unrecognized BigInteger implementation"); } + + _data = bOut.toByteArray(); } public void nextBytes(byte[] bytes) { System.arraycopy(_data, _index, bytes, 0, bytes.length); - + _index += bytes.length; } - + + public byte[] generateSeed(int numBytes) + { + byte[] bytes = new byte[numBytes]; + + this.nextBytes(bytes); + + return bytes; + } + // // classpath's implementation of SecureRandom doesn't currently go back to nextBytes // when next is called. We can't override next as it's a final method. @@ -81,25 +236,9 @@ val |= nextValue() << 24; val |= nextValue() << 16; - - if (_intPad == 2) - { - _intPad--; - } - else - { - val |= nextValue() << 8; - } - - if (_intPad == 1) - { - _intPad--; - } - else - { - val |= nextValue(); - } - + val |= nextValue() << 8; + val |= nextValue(); + return val; } @@ -132,4 +271,65 @@ { return _data[_index++] & 0xff; } + + private static class RandomChecker + extends SecureRandom + { + RandomChecker() + { + super(null, new DummyProvider()); // to prevent recursion in provider creation + } + + byte[] data = Hex.decode("01020304ffffffff0506070811111111"); + int index = 0; + + public void nextBytes(byte[] bytes) + { + System.arraycopy(data, index, bytes, 0, bytes.length); + + index += bytes.length; + } + } + + private static byte[] expandToBitLength(int bitLength, byte[] v) + { + if ((bitLength + 7) / 8 > v.length) + { + byte[] tmp = new byte[(bitLength + 7) / 8]; + + System.arraycopy(v, 0, tmp, tmp.length - v.length, v.length); + if (isAndroidStyle) + { + if (bitLength % 8 != 0) + { + int i = Pack.bigEndianToInt(tmp, 0); + Pack.intToBigEndian(i << (8 - (bitLength % 8)), tmp, 0); + } + } + + return tmp; + } + else + { + if (isAndroidStyle && bitLength < (v.length * 8)) + { + if (bitLength % 8 != 0) + { + int i = Pack.bigEndianToInt(v, 0); + Pack.intToBigEndian(i << (8 - (bitLength % 8)), v, 0); + } + } + } + + return v; + } + + private static class DummyProvider + extends Provider + { + DummyProvider() + { + super("BCFIPS_FIXED_RNG", 1.0, "BCFIPS Fixed Secure Random Provider"); + } + } } diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/util/test/TestRandomBigInteger.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/util/test/TestRandomBigInteger.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/util/test/TestRandomBigInteger.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/util/test/TestRandomBigInteger.java 2016-09-27 21:01:35.000000000 +0000 @@ -0,0 +1,52 @@ +package org.bouncycastle.util.test; + +import org.bouncycastle.util.BigIntegers; + +/** + * A fixed secure random designed to return data for someone needing to create a single BigInteger. + */ +public class TestRandomBigInteger + extends FixedSecureRandom +{ + /** + * Constructor from a base 10 represention of a BigInteger. + * + * @param encoding a base 10 represention of a BigInteger. + */ + public TestRandomBigInteger(String encoding) + { + this(encoding, 10); + } + + /** + * Constructor from a base radix represention of a BigInteger. + * + * @param encoding a String BigInteger of base radix. + * @param radix the radix to use. + */ + public TestRandomBigInteger(String encoding, int radix) + { + super(new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(BigIntegers.asUnsignedByteArray(new java.math.BigInteger(encoding, radix))) }); + } + + /** + * Constructor based on a byte array. + * + * @param encoding a 2's complement representation of the BigInteger. + */ + public TestRandomBigInteger(byte[] encoding) + { + super(new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(encoding) }); + } + + /** + * Constructor which ensures encoding will produce a BigInteger from a request from the passed in bitLength. + * + * @param bitLength bit length for the BigInteger data request. + * @param encoding bytes making up the encoding. + */ + public TestRandomBigInteger(int bitLength, byte[] encoding) + { + super(new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(bitLength, encoding) }); + } +} diff -Nru bouncycastle-1.55/core/src/main/java/org/bouncycastle/util/test/TestRandomData.java bouncycastle-1.56/core/src/main/java/org/bouncycastle/util/test/TestRandomData.java --- bouncycastle-1.55/core/src/main/java/org/bouncycastle/util/test/TestRandomData.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/java/org/bouncycastle/util/test/TestRandomData.java 2016-09-28 00:59:39.000000000 +0000 @@ -0,0 +1,30 @@ +package org.bouncycastle.util.test; + +import org.bouncycastle.util.encoders.Hex; + +/** + * A fixed secure random designed to return data for someone needing random bytes. + */ +public class TestRandomData + extends FixedSecureRandom +{ + /** + * Constructor from a Hex encoding of the data. + * + * @param encoding a Hex encoding of the data to be returned. + */ + public TestRandomData(String encoding) + { + super(new Source[] { new FixedSecureRandom.Data(Hex.decode(encoding)) }); + } + + /** + * Constructor from an array of bytes. + * + * @param encoding a byte array representing the data to be returned. + */ + public TestRandomData(byte[] encoding) + { + super(new Source[] { new FixedSecureRandom.Data(encoding) }); + } +} diff -Nru bouncycastle-1.55/core/src/main/jdk1.1/org/bouncycastle/crypto/encodings/PKCS1Encoding.java bouncycastle-1.56/core/src/main/jdk1.1/org/bouncycastle/crypto/encodings/PKCS1Encoding.java --- bouncycastle-1.55/core/src/main/jdk1.1/org/bouncycastle/crypto/encodings/PKCS1Encoding.java 2015-10-08 00:39:11.000000000 +0000 +++ bouncycastle-1.56/core/src/main/jdk1.1/org/bouncycastle/crypto/encodings/PKCS1Encoding.java 2016-12-20 01:53:07.000000000 +0000 @@ -7,6 +7,7 @@ import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.util.Arrays; /** * this does your basic PKCS 1 v1.5 padding - whether or not you should be using this @@ -32,33 +33,35 @@ private static final int HEADER_LENGTH = 10; - private SecureRandom random; - private AsymmetricBlockCipher engine; - private boolean forEncryption; - private boolean forPrivateKey; - private boolean useStrictLength; - private int pLen = -1; - private byte[] fallback = null; + private SecureRandom random; + private AsymmetricBlockCipher engine; + private boolean forEncryption; + private boolean forPrivateKey; + private boolean useStrictLength; + private int pLen = -1; + private byte[] fallback = null; + private byte[] blockBuffer; /** * Basic constructor. + * * @param cipher */ public PKCS1Encoding( - AsymmetricBlockCipher cipher) + AsymmetricBlockCipher cipher) { this.engine = cipher; this.useStrictLength = useStrict(); - } + } /** * Constructor for decryption with a fixed plaintext length. - * + * * @param cipher The cipher to use for cryptographic operation. - * @param pLen Length of the expected plaintext. + * @param pLen Length of the expected plaintext. */ public PKCS1Encoding( - AsymmetricBlockCipher cipher, + AsymmetricBlockCipher cipher, int pLen) { this.engine = cipher; @@ -66,27 +69,24 @@ this.pLen = pLen; } - /** - * Constructor for decryption with a fixed plaintext length and a fallback - * value that is returned, if the padding is incorrect. - * - * @param cipher - * The cipher to use for cryptographic operation. - * @param fallback - * The fallback value, we don't to a arraycopy here. - */ - public PKCS1Encoding( - AsymmetricBlockCipher cipher, + /** + * Constructor for decryption with a fixed plaintext length and a fallback + * value that is returned, if the padding is incorrect. + * + * @param cipher The cipher to use for cryptographic operation. + * @param fallback The fallback value, we don't do an arraycopy here. + */ + public PKCS1Encoding( + AsymmetricBlockCipher cipher, byte[] fallback) { - this.engine = cipher; - this.useStrictLength = useStrict(); - this.fallback = fallback; - this.pLen = fallback.length; + this.engine = cipher; + this.useStrictLength = useStrict(); + this.fallback = fallback; + this.pLen = fallback.length; } - - + // // for J2ME compatibility // @@ -110,33 +110,42 @@ } public void init( - boolean forEncryption, - CipherParameters param) + boolean forEncryption, + CipherParameters param) { - AsymmetricKeyParameter kParam; + AsymmetricKeyParameter kParam; if (param instanceof ParametersWithRandom) { - ParametersWithRandom rParam = (ParametersWithRandom)param; + ParametersWithRandom rParam = (ParametersWithRandom)param; this.random = rParam.getRandom(); kParam = (AsymmetricKeyParameter)rParam.getParameters(); } else { - this.random = new SecureRandom(); kParam = (AsymmetricKeyParameter)param; + if (!kParam.isPrivate() && forEncryption) + { + this.random = new SecureRandom(); + } } engine.init(forEncryption, param); this.forPrivateKey = kParam.isPrivate(); this.forEncryption = forEncryption; + this.blockBuffer = new byte[engine.getOutputBlockSize()]; + + if (pLen > 0 && fallback == null && random == null) + { + throw new IllegalArgumentException("encoder requires random"); + } } public int getInputBlockSize() { - int baseBlockSize = engine.getInputBlockSize(); + int baseBlockSize = engine.getInputBlockSize(); if (forEncryption) { @@ -150,7 +159,7 @@ public int getOutputBlockSize() { - int baseBlockSize = engine.getOutputBlockSize(); + int baseBlockSize = engine.getOutputBlockSize(); if (forEncryption) { @@ -163,9 +172,9 @@ } public byte[] processBlock( - byte[] in, - int inOff, - int inLen) + byte[] in, + int inOff, + int inLen) throws InvalidCipherTextException { if (forEncryption) @@ -179,17 +188,17 @@ } private byte[] encodeBlock( - byte[] in, - int inOff, - int inLen) + byte[] in, + int inOff, + int inLen) throws InvalidCipherTextException { if (inLen > getInputBlockSize()) { throw new IllegalArgumentException("input data too large"); } - - byte[] block = new byte[engine.getInputBlockSize()]; + + byte[] block = new byte[engine.getInputBlockSize()]; if (forPrivateKey) { @@ -224,62 +233,63 @@ return engine.processBlock(block, 0, block.length); } - + /** * Checks if the argument is a correctly PKCS#1.5 encoded Plaintext * for encryption. - * + * * @param encoded The Plaintext. - * @param pLen Expected length of the plaintext. + * @param pLen Expected length of the plaintext. * @return Either 0, if the encoding is correct, or -1, if it is incorrect. */ - private static int checkPkcs1Encoding(byte[] encoded, int pLen) { - int correct = 0; - /* + private static int checkPkcs1Encoding(byte[] encoded, int pLen) + { + int correct = 0; + /* * Check if the first two bytes are 0 2 */ - correct |= (encoded[0] ^ 2); + correct |= (encoded[0] ^ 2); /* * Now the padding check, check for no 0 byte in the padding */ - int plen = encoded.length - ( - pLen /* Lenght of the PMS */ - + 1 /* Final 0-byte before PMS */ - ); - - for (int i = 1; i < plen; i++) { - int tmp = encoded[i]; - tmp |= tmp >> 1; - tmp |= tmp >> 2; - tmp |= tmp >> 4; - correct |= (tmp & 1) - 1; - } + int plen = encoded.length - ( + pLen /* Lenght of the PMS */ + + 1 /* Final 0-byte before PMS */ + ); + + for (int i = 1; i < plen; i++) + { + int tmp = encoded[i]; + tmp |= tmp >> 1; + tmp |= tmp >> 2; + tmp |= tmp >> 4; + correct |= (tmp & 1) - 1; + } /* * Make sure the padding ends with a 0 byte. */ - correct |= encoded[encoded.length - (pLen +1)]; + correct |= encoded[encoded.length - (pLen + 1)]; /* * Return 0 or 1, depending on the result. */ - correct |= correct >> 1; - correct |= correct >> 2; - correct |= correct >> 4; - return ~((correct & 1) - 1); - } - + correct |= correct >> 1; + correct |= correct >> 2; + correct |= correct >> 4; + return ~((correct & 1) - 1); + } + /** * Decode PKCS#1.5 encoding, and return a random value if the padding is not correct. - * - * @param in The encrypted block. + * + * @param in The encrypted block. * @param inOff Offset in the encrypted block. * @param inLen Length of the encrypted block. - * //@param pLen Length of the desired output. + * //@param pLen Length of the desired output. * @return The plaintext without padding, or a random value if the padding was incorrect. - * * @throws InvalidCipherTextException */ private byte[] decodeBlockOrRandom(byte[] in, int inOff, int inLen) @@ -291,7 +301,7 @@ } byte[] block = engine.processBlock(in, inOff, inLen); - byte[] random = null; + byte[] random; if (this.fallback == null) { random = new byte[this.pLen]; @@ -302,30 +312,12 @@ random = fallback; } - /* - * TODO: This is a potential dangerous side channel. However, you can - * fix this by changing the RSA engine in a way, that it will always - * return blocks of the same length and prepend them with 0 bytes if - * needed. - */ - if (block.length < getOutputBlockSize()) - { - throw new InvalidCipherTextException("block truncated"); - } - - /* - * TODO: Potential side channel. Fix it by making the engine always - * return blocks of the correct length. - */ - if (useStrictLength && block.length != engine.getOutputBlockSize()) - { - throw new InvalidCipherTextException("block incorrect size"); - } + byte[] data = (useStrictLength & (block.length != engine.getOutputBlockSize())) ? blockBuffer : block; /* * Check the padding. */ - int correct = PKCS1Encoding.checkPkcs1Encoding(block, this.pLen); + int correct = PKCS1Encoding.checkPkcs1Encoding(data, this.pLen); /* * Now, to a constant time constant memory copy of the decrypted value @@ -334,88 +326,106 @@ byte[] result = new byte[this.pLen]; for (int i = 0; i < this.pLen; i++) { - result[i] = (byte)((block[i + (block.length - pLen)] & (~correct)) | (random[i] & correct)); + result[i] = (byte)((data[i + (data.length - pLen)] & (~correct)) | (random[i] & correct)); } + Arrays.fill(data, (byte)0); + return result; } /** - * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format. + * @throws InvalidCipherTextException if the decrypted block is not in PKCS1 format. */ private byte[] decodeBlock( - byte[] in, - int inOff, - int inLen) + byte[] in, + int inOff, + int inLen) throws InvalidCipherTextException { /* * If the length of the expected plaintext is known, we use a constant-time decryption. * If the decryption fails, we return a random value. */ - if (this.pLen != -1) { - return this.decodeBlockOrRandom(in, inOff, inLen); - } - + if (this.pLen != -1) + { + return this.decodeBlockOrRandom(in, inOff, inLen); + } + byte[] block = engine.processBlock(in, inOff, inLen); + boolean incorrectLength = (useStrictLength & (block.length != engine.getOutputBlockSize())); + byte[] data; if (block.length < getOutputBlockSize()) { - throw new InvalidCipherTextException("block truncated"); + data = blockBuffer; + } + else + { + data = block; } - byte type = block[0]; + byte type = data[0]; + boolean badType; if (forPrivateKey) { - if (type != 2) - { - throw new InvalidCipherTextException("unknown block type"); - } + badType = (type != 2); } else { - if (type != 1) - { - throw new InvalidCipherTextException("unknown block type"); - } + badType = (type != 1); } - if (useStrictLength && block.length != engine.getOutputBlockSize()) - { - throw new InvalidCipherTextException("block incorrect size"); - } - // // find and extract the message block. // - int start; - - for (start = 1; start != block.length; start++) - { - byte pad = block[start]; - - if (pad == 0) - { - break; - } - if (type == 1 && pad != (byte)0xff) - { - throw new InvalidCipherTextException("block padding incorrect"); - } - } + int start = findStart(type, data); start++; // data should start at the next byte - if (start > block.length || start < HEADER_LENGTH) + if (badType | start < HEADER_LENGTH) + { + Arrays.fill(data, (byte)0); + throw new InvalidCipherTextException("block incorrect"); + } + + // if we get this far, it's likely to be a genuine encoding error + if (incorrectLength) { - throw new InvalidCipherTextException("no data in block"); + Arrays.fill(data, (byte)0); + throw new InvalidCipherTextException("block incorrect size"); } - byte[] result = new byte[block.length - start]; + byte[] result = new byte[data.length - start]; - System.arraycopy(block, start, result, 0, result.length); + System.arraycopy(data, start, result, 0, result.length); return result; } + + private int findStart(byte type, byte[] block) + throws InvalidCipherTextException + { + int start = -1; + boolean padErr = false; + + for (int i = 1; i != block.length; i++) + { + byte pad = block[i]; + + if (pad == 0 & start < 0) + { + start = i; + } + padErr |= (type == 1 & start < 0 & pad != (byte)0xff); + } + + if (padErr) + { + return -1; + } + + return start; + } } diff -Nru bouncycastle-1.55/core/src/main/jdk1.1/org/bouncycastle/util/test/FixedSecureRandom.java bouncycastle-1.56/core/src/main/jdk1.1/org/bouncycastle/util/test/FixedSecureRandom.java --- bouncycastle-1.55/core/src/main/jdk1.1/org/bouncycastle/util/test/FixedSecureRandom.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/jdk1.1/org/bouncycastle/util/test/FixedSecureRandom.java 2016-12-20 05:51:42.000000000 +0000 @@ -0,0 +1,326 @@ +package org.bouncycastle.util.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.Provider; +import java.security.SecureRandom; + +import org.bouncycastle.util.Pack; +import org.bouncycastle.util.encoders.Hex; + +/** + * A secure random that returns pre-seeded data to calls of nextBytes() or generateSeed(). + */ +public class FixedSecureRandom + extends SecureRandom +{ + private static java.math.BigInteger REGULAR = new java.math.BigInteger("01020304ffffffff0506070811111111", 16); + private static java.math.BigInteger ANDROID = new java.math.BigInteger("1111111105060708ffffffff01020304", 16); + private static java.math.BigInteger CLASSPATH = new java.math.BigInteger("3020104ffffffff05060708111111", 16); + + private static final boolean isAndroidStyle; + private static final boolean isClasspathStyle; + private static final boolean isRegularStyle; + + static + { + java.math.BigInteger check1 = new java.math.BigInteger(128, new RandomChecker()); + java.math.BigInteger check2 = new java.math.BigInteger(120, new RandomChecker()); + + isAndroidStyle = check1.equals(ANDROID); + isRegularStyle = check1.equals(REGULAR); + isClasspathStyle = check2.equals(CLASSPATH); + } + + private byte[] _data; + private int _index; + + /** + * Base class for sources of fixed "Randomness" + */ + public static class Source + { + byte[] data; + + Source(byte[] data) + { + this.data = data; + } + } + + /** + * Data Source - in this case we just expect requests for byte arrays. + */ + public static class Data + extends Source + { + public Data(byte[] data) + { + super(data); + } + } + + /** + * BigInteger Source - in this case we expect requests for data that will be used + * for BigIntegers. The FixedSecureRandom will attempt to compensate for platform differences here. + */ + public static class BigInteger + extends Source + { + public BigInteger(byte[] data) + { + super(data); + } + + public BigInteger(int bitLength, byte[] data) + { + super(expandToBitLength(bitLength, data)); + } + + public BigInteger(String hexData) + { + this(Hex.decode(hexData)); + } + + public BigInteger(int bitLength, String hexData) + { + super(expandToBitLength(bitLength, Hex.decode(hexData))); + } + } + + public FixedSecureRandom(byte[] value) + { + this(new Source[] { new Data(value) }); + } + + public FixedSecureRandom( + byte[][] values) + { + this(buildDataArray(values)); + } + + private static Data[] buildDataArray(byte[][] values) + { + Data[] res = new Data[values.length]; + + for (int i = 0; i != values.length; i++) + { + res[i] = new Data(values[i]); + } + + return res; + } + + public FixedSecureRandom( + Source[] sources) + { + super(null); // to prevent recursion in provider creation + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + if (isRegularStyle) + { + if (isClasspathStyle) + { + for (int i = 0; i != sources.length; i++) + { + try + { + if (sources[i] instanceof BigInteger) + { + byte[] data = sources[i].data; + int len = data.length - (data.length % 4); + for (int w = data.length - len - 1; w >= 0; w--) + { + bOut.write(data[w]); + } + for (int w = data.length - len; w < data.length; w += 4) + { + bOut.write(data, w, 4); + } + } + else + { + bOut.write(sources[i].data); + } + } + catch (IOException e) + { + throw new IllegalArgumentException("can't save value source."); + } + } + } + else + { + for (int i = 0; i != sources.length; i++) + { + try + { + bOut.write(sources[i].data); + } + catch (IOException e) + { + throw new IllegalArgumentException("can't save value source."); + } + } + } + } + else if (isAndroidStyle) + { + for (int i = 0; i != sources.length; i++) + { + try + { + if (sources[i] instanceof BigInteger) + { + byte[] data = sources[i].data; + int len = data.length - (data.length % 4); + for (int w = 0; w < len; w += 4) + { + bOut.write(data, data.length - (w + 4), 4); + } + if (data.length - len != 0) + { + for (int w = 0; w != 4 - (data.length - len); w++) + { + bOut.write(0); + } + } + for (int w = 0; w != data.length - len; w++) + { + bOut.write(data[len + w]); + } + } + else + { + bOut.write(sources[i].data); + } + } + catch (IOException e) + { + throw new IllegalArgumentException("can't save value source."); + } + } + } + else + { + throw new IllegalStateException("Unrecognized BigInteger implementation"); + } + + _data = bOut.toByteArray(); + } + + public void nextBytes(byte[] bytes) + { + System.arraycopy(_data, _index, bytes, 0, bytes.length); + + _index += bytes.length; + } + + public byte[] generateSeed(int numBytes) + { + byte[] bytes = new byte[numBytes]; + + this.nextBytes(bytes); + + return bytes; + } + + // + // classpath's implementation of SecureRandom doesn't currently go back to nextBytes + // when next is called. We can't override next as it's a final method. + // + public int nextInt() + { + int val = 0; + + val |= nextValue() << 24; + val |= nextValue() << 16; + val |= nextValue() << 8; + val |= nextValue(); + + return val; + } + + // + // classpath's implementation of SecureRandom doesn't currently go back to nextBytes + // when next is called. We can't override next as it's a final method. + // + public long nextLong() + { + long val = 0; + + val |= (long)nextValue() << 56; + val |= (long)nextValue() << 48; + val |= (long)nextValue() << 40; + val |= (long)nextValue() << 32; + val |= (long)nextValue() << 24; + val |= (long)nextValue() << 16; + val |= (long)nextValue() << 8; + val |= (long)nextValue(); + + return val; + } + + public boolean isExhausted() + { + return _index == _data.length; + } + + private int nextValue() + { + return _data[_index++] & 0xff; + } + + private static class RandomChecker + extends SecureRandom + { + RandomChecker() + { + super(null); // to prevent recursion in provider creation + } + + byte[] data = Hex.decode("01020304ffffffff0506070811111111"); + int index = 0; + + public void nextBytes(byte[] bytes) + { + System.arraycopy(data, index, bytes, 0, bytes.length); + + index += bytes.length; + } + } + + private static byte[] expandToBitLength(int bitLength, byte[] v) + { + if ((bitLength + 7) / 8 > v.length) + { + byte[] tmp = new byte[(bitLength + 7) / 8]; + + System.arraycopy(v, 0, tmp, tmp.length - v.length, v.length); + if (isAndroidStyle) + { + if (bitLength % 8 != 0) + { + int i = Pack.bigEndianToInt(tmp, 0); + Pack.intToBigEndian(i << (8 - (bitLength % 8)), tmp, 0); + } + } + + return tmp; + } + else + { + if (isAndroidStyle && bitLength < (v.length * 8)) + { + if (bitLength % 8 != 0) + { + int i = Pack.bigEndianToInt(v, 0); + Pack.intToBigEndian(i << (8 - (bitLength % 8)), v, 0); + } + } + } + + return v; + } +} diff -Nru bouncycastle-1.55/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1ObjectIdentifier.java bouncycastle-1.56/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1ObjectIdentifier.java --- bouncycastle-1.55/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1ObjectIdentifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1ObjectIdentifier.java 2016-08-21 23:40:53.000000000 +0000 @@ -0,0 +1,484 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.util.Arrays; + +/** + * Class representing the ASN.1 OBJECT IDENTIFIER type. + */ +public class ASN1ObjectIdentifier + extends ASN1Primitive +{ + private final String identifier; + + private byte[] body; + + /** + * return an OID from the passed in object + * @param obj an ASN1ObjectIdentifier or an object that can be converted into one. + * @throws IllegalArgumentException if the object cannot be converted. + * @return an ASN1ObjectIdentifier instance, or null. + */ + public static ASN1ObjectIdentifier getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)obj; + } + + if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive(); + } + + if (obj instanceof byte[]) + { + byte[] enc = (byte[])obj; + try + { + return (ASN1ObjectIdentifier)fromByteArray(enc); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct object identifier from byte[]: " + e.getMessage()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Object Identifier from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @throws IllegalArgumentException if the tagged object cannot + * be converted. + * @return an ASN1ObjectIdentifier instance, or null. + */ + public static ASN1ObjectIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof ASN1ObjectIdentifier) + { + return getInstance(o); + } + else + { + return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + } + } + + private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f; + + ASN1ObjectIdentifier( + byte[] bytes) + { + StringBuffer objId = new StringBuffer(); + long value = 0; + BigInteger bigValue = null; + boolean first = true; + + for (int i = 0; i != bytes.length; i++) + { + int b = bytes[i] & 0xff; + + if (value <= LONG_LIMIT) + { + value += (b & 0x7f); + if ((b & 0x80) == 0) // end of number reached + { + if (first) + { + if (value < 40) + { + objId.append('0'); + } + else if (value < 80) + { + objId.append('1'); + value -= 40; + } + else + { + objId.append('2'); + value -= 80; + } + first = false; + } + + objId.append('.'); + objId.append(value); + value = 0; + } + else + { + value <<= 7; + } + } + else + { + if (bigValue == null) + { + bigValue = BigInteger.valueOf(value); + } + bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f)); + if ((b & 0x80) == 0) + { + if (first) + { + objId.append('2'); + bigValue = bigValue.subtract(BigInteger.valueOf(80)); + first = false; + } + + objId.append('.'); + objId.append(bigValue); + bigValue = null; + value = 0; + } + else + { + bigValue = bigValue.shiftLeft(7); + } + } + } + + this.identifier = objId.toString(); + this.body = Arrays.clone(bytes); + } + + /** + * Create an OID based on the passed in String. + * + * @param identifier a string representation of an OID. + */ + public ASN1ObjectIdentifier( + String identifier) + { + if (identifier == null) + { + throw new IllegalArgumentException("'identifier' cannot be null"); + } + if (!isValidIdentifier(identifier)) + { + throw new IllegalArgumentException("string " + identifier + " not an OID"); + } + + this.identifier = identifier; + } + + /** + * Create an OID that creates a branch under the current one. + * + * @param branchID node numbers for the new branch. + * @return the OID for the new created branch. + */ + ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branchID) + { + if (!isValidBranchID(branchID, 0)) + { + throw new IllegalArgumentException("string " + branchID + " not a valid OID branch"); + } + + this.identifier = oid.getId() + "." + branchID; + } + + /** + * Return the OID as a string. + * + * @return the string representation of the OID carried by this object. + */ + public String getId() + { + return identifier; + } + + /** + * Return an OID that creates a branch under the current one. + * + * @param branchID node numbers for the new branch. + * @return the OID for the new created branch. + */ + public ASN1ObjectIdentifier branch(String branchID) + { + return new ASN1ObjectIdentifier(this, branchID); + } + + /** + * Return true if this oid is an extension of the passed in branch, stem. + * + * @param stem the arc or branch that is a possible parent. + * @return true if the branch is on the passed in stem, false otherwise. + */ + public boolean on(ASN1ObjectIdentifier stem) + { + String id = getId(), stemId = stem.getId(); + return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId); + } + + private void writeField( + ByteArrayOutputStream out, + long fieldValue) + { + byte[] result = new byte[9]; + int pos = 8; + result[pos] = (byte)((int)fieldValue & 0x7f); + while (fieldValue >= (1L << 7)) + { + fieldValue >>= 7; + result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80); + } + out.write(result, pos, 9 - pos); + } + + private void writeField( + ByteArrayOutputStream out, + BigInteger fieldValue) + { + int byteCount = (fieldValue.bitLength() + 6) / 7; + if (byteCount == 0) + { + out.write(0); + } + else + { + BigInteger tmpValue = fieldValue; + byte[] tmp = new byte[byteCount]; + for (int i = byteCount - 1; i >= 0; i--) + { + tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80); + tmpValue = tmpValue.shiftRight(7); + } + tmp[byteCount - 1] &= 0x7f; + out.write(tmp, 0, tmp.length); + } + } + + private void doOutput(ByteArrayOutputStream aOut) + { + OIDTokenizer tok = new OIDTokenizer(identifier); + int first = Integer.parseInt(tok.nextToken()) * 40; + + String secondToken = tok.nextToken(); + if (secondToken.length() <= 18) + { + writeField(aOut, first + Long.parseLong(secondToken)); + } + else + { + writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first))); + } + + while (tok.hasMoreTokens()) + { + String token = tok.nextToken(); + if (token.length() <= 18) + { + writeField(aOut, Long.parseLong(token)); + } + else + { + writeField(aOut, new BigInteger(token)); + } + } + } + + private synchronized byte[] getBody() + { + if (body == null) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + doOutput(bOut); + + body = bOut.toByteArray(); + } + + return body; + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + throws IOException + { + int length = getBody().length; + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + byte[] enc = getBody(); + + out.write(BERTags.OBJECT_IDENTIFIER); + out.writeLength(enc.length); + out.write(enc); + } + + public int hashCode() + { + return identifier.hashCode(); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof ASN1ObjectIdentifier)) + { + return false; + } + + return identifier.equals(((ASN1ObjectIdentifier)o).identifier); + } + + public String toString() + { + return getId(); + } + + private static boolean isValidBranchID( + String branchID, int start) + { + boolean periodAllowed = false; + + int pos = branchID.length(); + while (--pos >= start) + { + char ch = branchID.charAt(pos); + + // TODO Leading zeroes? + if ('0' <= ch && ch <= '9') + { + periodAllowed = true; + continue; + } + + if (ch == '.') + { + if (!periodAllowed) + { + return false; + } + + periodAllowed = false; + continue; + } + + return false; + } + + return periodAllowed; + } + + private static boolean isValidIdentifier( + String identifier) + { + if (identifier.length() < 3 || identifier.charAt(1) != '.') + { + return false; + } + + char first = identifier.charAt(0); + if (first < '0' || first > '2') + { + return false; + } + + return isValidBranchID(identifier, 2); + } + + /** + * Intern will return a reference to a pooled version of this object, unless it + * is not present in which case intern will add it. + *

+ * The pool is also used by the ASN.1 parsers to limit the number of duplicated OID + * objects in circulation. + *

+ * @return a reference to the identifier in the pool. + */ + public ASN1ObjectIdentifier intern() + { + synchronized (pool) + { + OidHandle hdl = new OidHandle(getBody()); + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)pool.get(hdl); + + if (oid != null) + { + return oid; + } + else + { + pool.put(hdl, this); + return this; + } + } + } + + private static final Map pool = new HashMap(); + + private static class OidHandle + { + private int key; + private final byte[] enc; + + OidHandle(byte[] enc) + { + this.key = Arrays.hashCode(enc); + this.enc = enc; + } + + public int hashCode() + { + return key; + } + + public boolean equals(Object o) + { + if (o instanceof OidHandle) + { + return Arrays.areEqual(enc, ((OidHandle)o).enc); + } + + return false; + } + } + + static ASN1ObjectIdentifier fromOctetString(byte[] enc) + { + OidHandle hdl = new OidHandle(enc); + + synchronized (pool) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)pool.get(hdl); + if (oid != null) + { + return oid; + } + } + + return new ASN1ObjectIdentifier(enc); + } +} diff -Nru bouncycastle-1.55/core/src/test/j2me/org/bouncycastle/crypto/test/RSATest.java bouncycastle-1.56/core/src/test/j2me/org/bouncycastle/crypto/test/RSATest.java --- bouncycastle-1.55/core/src/test/j2me/org/bouncycastle/crypto/test/RSATest.java 2015-12-29 02:32:47.000000000 +0000 +++ bouncycastle-1.56/core/src/test/j2me/org/bouncycastle/crypto/test/RSATest.java 2016-12-21 07:24:26.000000000 +0000 @@ -6,11 +6,14 @@ import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.encodings.OAEPEncoding; import org.bouncycastle.crypto.encodings.PKCS1Encoding; import org.bouncycastle.crypto.engines.RSAEngine; import org.bouncycastle.crypto.generators.RSAKeyPairGenerator; +import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.params.RSAKeyGenerationParameters; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; @@ -21,14 +24,14 @@ public class RSATest extends SimpleTest { - static BigInteger mod = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16); - static BigInteger pubExp = new BigInteger("11", 16); - static BigInteger privExp = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16); - static BigInteger p = new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16); - static BigInteger q = new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16); - static BigInteger pExp = new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16); - static BigInteger qExp = new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16); - static BigInteger crtCoef = new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16); + static BigInteger mod = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16); + static BigInteger pubExp = new BigInteger("11", 16); + static BigInteger privExp = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16); + static BigInteger p = new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16); + static BigInteger q = new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16); + static BigInteger pExp = new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16); + static BigInteger qExp = new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16); + static BigInteger crtCoef = new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16); static String input = "4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; @@ -36,7 +39,7 @@ // to check that we handling byte extension by big number correctly. // static String edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; - + static byte[] oversizedSig = Hex.decode("01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); static byte[] dudBlock = Hex.decode("000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); static byte[] truncatedDataBlock = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); @@ -50,29 +53,30 @@ private void testStrictPKCS1Length(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - AsymmetricBlockCipher eng = new RSAEngine(); + AsymmetricBlockCipher eng = new RSAEngine(); eng.init(true, privParameters); - + byte[] data = null; - + byte[] overSized = null; + try { - data = eng.processBlock(oversizedSig, 0, oversizedSig.length); + overSized = data = eng.processBlock(oversizedSig, 0, oversizedSig.length); } catch (Exception e) { fail("RSA: failed - exception " + e.toString(), e); } - + eng = new PKCS1Encoding(eng); - + eng.init(false, pubParameters); - + try { - data = eng.processBlock(data, 0, data.length); - + data = eng.processBlock(overSized, 0, overSized.length); + fail("oversized signature block not recognised"); } catch (InvalidCipherTextException e) @@ -82,36 +86,49 @@ fail("RSA: failed - exception " + e.toString(), e); } } + + eng = new PKCS1Encoding(new RSAEngine(), Hex.decode("feedbeeffeedbeeffeedbeef")); + eng.init(false, new ParametersWithRandom(privParameters, new SecureRandom())); + + try + { + data = eng.processBlock(overSized, 0, overSized.length); + isTrue("not fallback", Arrays.areEqual(Hex.decode("feedbeeffeedbeeffeedbeef"), data)); + } + catch (InvalidCipherTextException e) + { + fail("RSA: failed - exception " + e.toString(), e); + } } - + private void testTruncatedPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block truncated"); + checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block incorrect"); } - + private void testDudPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "unknown block type"); + checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "block incorrect"); } private void testWrongPaddingPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block padding incorrect"); + checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block incorrect"); } - + private void testMissingDataPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "no data in block"); + checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "block incorrect"); } private void checkForPKCS1Exception(RSAKeyParameters pubParameters, RSAKeyParameters privParameters, byte[] inputData, String expectedMessage) { - AsymmetricBlockCipher eng = new RSAEngine(); + AsymmetricBlockCipher eng = new RSAEngine(); eng.init(true, privParameters); - + byte[] data = null; - + try { data = eng.processBlock(inputData, 0, inputData.length); @@ -120,15 +137,15 @@ { fail("RSA: failed - exception " + e.toString(), e); } - + eng = new PKCS1Encoding(eng); - + eng.init(false, pubParameters); - + try { data = eng.processBlock(data, 0, data.length); - + fail("missing data block not recognised"); } catch (InvalidCipherTextException e) @@ -139,7 +156,7 @@ } } } - + private void testOAEP(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { // @@ -174,6 +191,28 @@ { fail("failed OAEP Test"); } + + // check for oversized input + byte[] message = new byte[87]; + RSAEngine rsaEngine = new RSAEngine(); + AsymmetricBlockCipher cipher = new OAEPEncoding(rsaEngine, new SHA1Digest(), new SHA1Digest(), message); + cipher.init(true, new ParametersWithRandom(pubParameters, new SecureRandom())); + + try + { + cipher.processBlock(message, 0, message.length); + + fail("no exception thrown"); + } + catch (DataLengthException e) + { + isTrue("message mismatch", "input data too long".equals(e.getMessage())); + } + catch (InvalidCipherTextException e) + { + fail("failed - exception " + e.toString(), e); + } + } private void zeroBlockTest(CipherParameters encParameters, CipherParameters decParameters) @@ -218,14 +257,14 @@ public void performTest() { - RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); - RSAKeyParameters privParameters = new RSAPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef); - byte[] data = Hex.decode(edgeInput); + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); + RSAKeyParameters privParameters = new RSAPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef); + byte[] data = Hex.decode(edgeInput); // // RAW // - AsymmetricBlockCipher eng = new RSAEngine(); + AsymmetricBlockCipher eng = new RSAEngine(); eng.init(true, pubParameters); @@ -289,7 +328,7 @@ eng = new PKCS1Encoding(eng); eng.init(true, pubParameters); - + if (eng.getOutputBlockSize() != ((PKCS1Encoding)eng).getUnderlyingCipher().getOutputBlockSize()) { fail("PKCS1 output block size incorrect"); @@ -306,85 +345,72 @@ eng.init(false, privParameters); + byte[] plainData = null; try { - data = eng.processBlock(data, 0, data.length); + plainData = eng.processBlock(data, 0, data.length); } catch (Exception e) { fail("failed - exception " + e.toString(), e); } - if (!input.equals(new String(Hex.encode(data)))) + if (!input.equals(Hex.toHexString(plainData))) { fail("failed PKCS1 public/private Test"); } - // - // PKCS1 - private encrypt, public decrypt - // - eng = new PKCS1Encoding(((PKCS1Encoding)eng).getUnderlyingCipher()); - - eng.init(true, privParameters); - + PKCS1Encoding fEng = new PKCS1Encoding(new RSAEngine(), input.length() / 2); + fEng.init(false, new ParametersWithRandom(privParameters, new SecureRandom())); try { - data = eng.processBlock(data, 0, data.length); + plainData = fEng.processBlock(data, 0, data.length); } catch (Exception e) { fail("failed - exception " + e.toString(), e); } - eng.init(false, pubParameters); + if (!input.equals(Hex.toHexString(plainData))) + { + fail("failed PKCS1 public/private fixed Test"); + } + fEng = new PKCS1Encoding(new RSAEngine(), input.length()); + fEng.init(false, new ParametersWithRandom(privParameters, new SecureRandom())); try { - data = eng.processBlock(data, 0, data.length); + data = fEng.processBlock(data, 0, data.length); } catch (Exception e) { fail("failed - exception " + e.toString(), e); } - if (!input.equals(new String(Hex.encode(data)))) + if (input.equals(Hex.toHexString(data))) { - fail("failed PKCS1 private/public Test"); + fail("failed to recognise incorrect plaint text length"); } - zeroBlockTest(pubParameters, privParameters); - zeroBlockTest(privParameters, pubParameters); + data = plainData; // - // key generation test + // PKCS1 - private encrypt, public decrypt // - RSAKeyPairGenerator pGen = new RSAKeyPairGenerator(); - RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters( - BigInteger.valueOf(0x11), new SecureRandom(), 768, 25); - - pGen.init(genParam); - - AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); - - eng = new RSAEngine(); - - if (((RSAKeyParameters)pair.getPublic()).getModulus().bitLength() < 768) - { - fail("failed key generation (768) length test"); - } + eng = new PKCS1Encoding(((PKCS1Encoding)eng).getUnderlyingCipher()); - eng.init(true, pair.getPublic()); + eng.init(true, privParameters); try { - data = eng.processBlock(data, 0, data.length); + data = eng.processBlock(plainData, 0, plainData.length); } catch (Exception e) { fail("failed - exception " + e.toString(), e); } - eng.init(false, pair.getPrivate()); + eng.init(false, pubParameters); try { @@ -395,23 +421,34 @@ fail("failed - exception " + e.toString(), e); } - if (!input.equals(new String(Hex.encode(data)))) + if (!input.equals(Hex.toHexString(data))) { - fail("failed key generation (768) Test"); + fail("failed PKCS1 private/public Test"); } - genParam = new RSAKeyGenerationParameters(BigInteger.valueOf(0x11), new SecureRandom(), 1024, 25); + zeroBlockTest(pubParameters, privParameters); + zeroBlockTest(privParameters, pubParameters); + + // + // key generation test + // + RSAKeyPairGenerator pGen = new RSAKeyPairGenerator(); + RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters( + BigInteger.valueOf(0x11), new SecureRandom(), 1024, 25); pGen.init(genParam); - pair = pGen.generateKeyPair(); - eng.init(true, pair.getPublic()); + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + eng = new RSAEngine(); if (((RSAKeyParameters)pair.getPublic()).getModulus().bitLength() < 1024) { fail("failed key generation (1024) length test"); } + eng.init(true, pair.getPublic()); + try { data = eng.processBlock(data, 0, data.length); @@ -434,25 +471,9 @@ if (!input.equals(new String(Hex.encode(data)))) { - fail("failed key generation (1024) test"); + fail("failed key generation (1024) Test"); } - genParam = new RSAKeyGenerationParameters( - BigInteger.valueOf(0x11), new SecureRandom(), 128, 25); - pGen.init(genParam); - - for (int i = 0; i < 100; ++i) - { - pair = pGen.generateKeyPair(); - RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters) pair.getPrivate(); - BigInteger pqDiff = privKey.getP().subtract(privKey.getQ()).abs(); - - if (pqDiff.bitLength() < 5) - { - fail("P and Q too close in RSA key pair"); - } - } - testOAEP(pubParameters, privParameters); testStrictPKCS1Length(pubParameters, privParameters); testDudPKCS1Block(pubParameters, privParameters); @@ -462,7 +483,7 @@ try { - new RSAEngine().processBlock(new byte[]{ 1 }, 0, 1); + new RSAEngine().processBlock(new byte[]{1}, 0, 1); fail("failed initialisation check"); } catch (IllegalStateException e) @@ -473,7 +494,7 @@ public static void main( - String[] args) + String[] args) { runTest(new RSATest()); } diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/asn1/test/MiscTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/asn1/test/MiscTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/asn1/test/MiscTest.java 2015-11-15 03:02:07.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/asn1/test/MiscTest.java 2016-10-15 00:21:01.000000000 +0000 @@ -5,7 +5,9 @@ import java.io.IOException; import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Enumerated; import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1OutputStream; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.BERSequence; @@ -67,6 +69,46 @@ } } + public void derIntegerTest() + throws Exception + { + try + { + new ASN1Integer(new byte[] { 0, 0, 0, 1}); + } + catch (IllegalArgumentException e) + { + isTrue("wrong exc", "malformed integer".equals(e.getMessage())); + } + + try + { + new ASN1Integer(new byte[] {(byte)0xff, (byte)0x80, 0, 1}); + } + catch (IllegalArgumentException e) + { + isTrue("wrong exc", "malformed integer".equals(e.getMessage())); + } + + try + { + new ASN1Enumerated(new byte[] { 0, 0, 0, 1}); + } + catch (IllegalArgumentException e) + { + isTrue("wrong exc", "malformed enumerated".equals(e.getMessage())); + } + + try + { + new ASN1Enumerated(new byte[] {(byte)0xff, (byte)0x80, 0, 1}); + } + catch (IllegalArgumentException e) + { + isTrue("wrong exc", "malformed enumerated".equals(e.getMessage())); + } + } + public void performTest() throws Exception { @@ -115,6 +157,7 @@ } shouldFailOnExtraData(); + derIntegerTest(); } public String getName() diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/asn1/test/ObjectIdentifierTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/asn1/test/ObjectIdentifierTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/asn1/test/ObjectIdentifierTest.java 2012-09-04 00:11:14.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/asn1/test/ObjectIdentifierTest.java 2016-08-23 02:10:25.000000000 +0000 @@ -16,13 +16,60 @@ throws Exception { // exercise the object cache - for (int i = 0; i < 1024; i++) + for (int i = 0; i < 100; i++) { - for (int j = 0; j != 17000; j++) + for (int j = 0; j < 100; j++) { - byte[] encoded = new ASN1ObjectIdentifier("1.1." + i + "." + j).getEncoded(); + final ASN1ObjectIdentifier oid1 = new ASN1ObjectIdentifier("1.1." + i + "." + j); + final byte[] encoded1 = oid1.getEncoded(); + final ASN1ObjectIdentifier oid2 = ASN1ObjectIdentifier.getInstance(encoded1); + if (oid1 == oid2) + { + fail("Shouldn't be the same: " + oid1 + " " + oid2); + } + if (!oid1.equals(oid2)) + { + fail("Should be equal: " + oid1 + " " + oid2); + } + final ASN1ObjectIdentifier oid3 = oid2.intern(); + if (oid2 != oid3) + { + fail("Should be the same: " + oid2 + " " + oid3); + } + if (!oid2.equals(oid3)) + { + fail("Should be equal: " + oid2 + " " + oid3); + } + final byte[] encoded2 = oid3.getEncoded(); + final ASN1ObjectIdentifier oid4 = ASN1ObjectIdentifier.getInstance(encoded2); + if (oid3 != oid4) + { + fail("Should be taken from cache: " + oid3 + " " + oid4); + } + if (!oid3.equals(oid4)) + { + fail("Should be equal: " + oid3 + " " + oid4); + } + } + } - ASN1ObjectIdentifier.getInstance(encoded); + // make sure we're not leaking memory + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 100; j++) + { + final ASN1ObjectIdentifier oid1 = new ASN1ObjectIdentifier("1.1.2." + i + "." + j); + final byte[] encoded1 = oid1.getEncoded(); + final ASN1ObjectIdentifier oid2 = ASN1ObjectIdentifier.getInstance(encoded1); + final ASN1ObjectIdentifier oid3 = ASN1ObjectIdentifier.getInstance(encoded1); + if (oid1 == oid2) + { + fail("Shouldn't be the same: " + oid1 + " " + oid2); + } + if (oid2 == oid3) + { + fail("Shouldn't be the same: " + oid2 + " " + oid3); + } } } } @@ -30,7 +77,7 @@ public static void main( String[] args) { - ObjectIdentifierTest test = new ObjectIdentifierTest(); + ObjectIdentifierTest test = new ObjectIdentifierTest(); TestResult result = test.perform(); System.out.println(result); diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/AESWrapPadTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/AESWrapPadTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/AESWrapPadTest.java 2015-10-06 04:31:54.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/AESWrapPadTest.java 2016-10-07 21:41:07.000000000 +0000 @@ -5,6 +5,7 @@ import org.bouncycastle.crypto.Wrapper; import org.bouncycastle.crypto.engines.AESWrapPadEngine; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; @@ -69,6 +70,31 @@ } } + private void wrapWithIVTest() + throws Exception + { + byte[] kek = Hex.decode("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"); + byte[] key = Hex.decode("c37b7e6492584340bed12207808941155068f738"); + byte[] expected = Hex.decode("5cbdb3fb71351d0e628b85dbcba1a1890d4db26d1335e11d1aabea11124caad0"); + + Wrapper wrapper = new AESWrapPadEngine(); + + wrapper.init(true, new ParametersWithIV(new KeyParameter(kek), Hex.decode("33333333"))); + + byte[] cipherText = wrapper.wrap(key, 0, key.length); + if (!areEqual(cipherText, expected)) + { + fail("Wrapped value does not match expected."); + } + wrapper.init(false, new ParametersWithIV(new KeyParameter(kek), Hex.decode("33333333"))); + byte[] plainText = wrapper.unwrap(cipherText, 0, cipherText.length); + + if (!areEqual(key, plainText)) + { + fail("Unwrapped value does not match original."); + } + } + public String getName() { return "AESWrapPad"; @@ -88,6 +114,7 @@ key = Hex.decode("466f7250617369"); wrapAndUnwrap(kek, key, wrap); + wrapWithIVTest(); // // offset test diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/cavp/CAVPReader.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/cavp/CAVPReader.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/cavp/CAVPReader.java 2013-07-26 05:24:55.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/cavp/CAVPReader.java 2016-11-07 00:29:07.000000000 +0000 @@ -15,7 +15,7 @@ import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA384Digest; import org.bouncycastle.crypto.digests.SHA512Digest; -import org.bouncycastle.crypto.engines.AESFastEngine; +import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.engines.DESedeEngine; import org.bouncycastle.crypto.macs.CMac; import org.bouncycastle.crypto.macs.HMac; @@ -109,7 +109,7 @@ final Mac prf; if (config.getProperty("PRF").matches("CMAC_AES\\d\\d\\d")) { - BlockCipher blockCipher = new AESFastEngine(); + BlockCipher blockCipher = new AESEngine(); prf = new CMac(blockCipher); } else if (config.getProperty("PRF").matches("CMAC_TDES\\d")) diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/CipherStreamTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/CipherStreamTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/CipherStreamTest.java 2015-01-05 07:01:09.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/CipherStreamTest.java 2016-11-04 04:04:40.000000000 +0000 @@ -43,7 +43,6 @@ import org.bouncycastle.crypto.modes.CFBBlockCipher; import org.bouncycastle.crypto.modes.CTSBlockCipher; import org.bouncycastle.crypto.modes.EAXBlockCipher; -import org.bouncycastle.crypto.modes.GCMBlockCipher; import org.bouncycastle.crypto.modes.NISTCTSBlockCipher; import org.bouncycastle.crypto.modes.OCBBlockCipher; import org.bouncycastle.crypto.modes.OFBBlockCipher; @@ -553,7 +552,8 @@ if (blockSize == 16) { testMode(new CCMBlockCipher(cipher1), new ParametersWithIV(key, new byte[7])); - testMode(new GCMBlockCipher(cipher1), withIv); + // TODO: need to have a GCM safe version of testMode. +// testMode(new GCMBlockCipher(cipher1), withIv); testMode(new OCBBlockCipher(cipher1, cipher2), new ParametersWithIV(key, new byte[15])); } } diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/DSATest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/DSATest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/DSATest.java 2016-04-25 02:31:06.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/DSATest.java 2016-10-15 02:12:46.000000000 +0000 @@ -26,6 +26,8 @@ import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomBigInteger; +import org.bouncycastle.util.test.TestRandomData; /** * Test based on FIPS 186-2, Appendix 5, an example of DSA, and FIPS 168-3 test vectors. @@ -36,12 +38,14 @@ byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); - SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2}); + SecureRandom random = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2) }); byte[] keyData = Hex.decode("b5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); - SecureRandom keyRandom = new FixedSecureRandom(new byte[][] { keyData, keyData }); - + SecureRandom keyRandom = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(Hex.decode("01020304"))}); + BigInteger pValue = new BigInteger("8df2a494492276aa3d25759bb06869cbeac0d83afb8d0cf7cbb8324f0d7882e5d0762fc5b7210eafc2e9adac32ab7aac49693dfbf83724c2ec0736ee31c80291", 16); BigInteger qValue = new BigInteger("c773218c737ec8ee993b4f2ded30f48edace915f", 16); @@ -161,7 +165,11 @@ "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16); DSAPrivateKeyParameters priKey = new DSAPrivateKeyParameters(x, dsaParams); - SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); + SecureRandom k = new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))), + new FixedSecureRandom.Data(Hex.decode("01020304")) + }); byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); @@ -257,7 +265,7 @@ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); - kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("D0EC4E50BB290A42E9E355C73D8809345DE2E139")), params)); + kpGen.init(new DSAKeyGenerationParameters(new TestRandomBigInteger("D0EC4E50BB290A42E9E355C73D8809345DE2E139", 16), params)); AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); @@ -283,7 +291,10 @@ DSASigner signer = new DSASigner(); - signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("349C55648DCF992F3F33E8026CFAC87C1D2BA075")))); + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger("349C55648DCF992F3F33E8026CFAC87C1D2BA075"), + new FixedSecureRandom.Data(Hex.decode("01020304")) }))); byte[] msg = Hex.decode("A9993E364706816ABA3E25717850C26C9CD0D89D"); @@ -369,7 +380,7 @@ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); - kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17")), params)); + kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17")), params)); AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); @@ -400,7 +411,11 @@ DSASigner signer = new DSASigner(); - signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("735959CC4463B8B440E407EECA8A473BF6A6D1FE657546F67D401F05")))); + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger(Hex.decode("735959CC4463B8B440E407EECA8A473BF6A6D1FE657546F67D401F05")), + new FixedSecureRandom.Data(Hex.decode("01020304")) + }))); byte[] msg = Hex.decode("23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); @@ -485,7 +500,7 @@ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); - kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), params)); + kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), params)); AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); @@ -516,7 +531,11 @@ DSASigner signer = new DSASigner(); - signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")))); + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), + new FixedSecureRandom.Data(Hex.decode("01020304")) + }))); byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"); @@ -611,7 +630,7 @@ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); - kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764")), params)); + kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764")), params)); AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); @@ -647,7 +666,10 @@ DSASigner signer = new DSASigner(); - signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("A6902C1E6E3943C5628061588A8B007BCCEA91DBF12915483F04B24AB0678BEE")))); + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] + { new FixedSecureRandom.BigInteger("A6902C1E6E3943C5628061588A8B007BCCEA91DBF12915483F04B24AB0678BEE"), + new FixedSecureRandom.Data(Hex.decode("01020304")) }))); byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"); @@ -678,7 +700,7 @@ } private class DSATestSecureRandom - extends FixedSecureRandom + extends TestRandomData { private boolean first = true; diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/DSTU4145Test.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/DSTU4145Test.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/DSTU4145Test.java 2013-11-08 01:25:25.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/DSTU4145Test.java 2016-09-29 23:44:55.000000000 +0000 @@ -12,8 +12,8 @@ import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomData; public class DSTU4145Test extends SimpleTest @@ -34,7 +34,7 @@ private void test163() throws Exception { - SecureRandom random = new FixedSecureRandom(Hex.decode("01025e40bd97db012b7a1d79de8e12932d247f61c6")); + SecureRandom random = new TestRandomData(Hex.decode("01025e40bd97db012b7a1d79de8e12932d247f61c6")); byte[] hash = Hex.decode("09c9c44277910c9aaee486883a2eb95b7180166ddf73532eeb76edaef52247ff"); for (int i = 0; i < hash.length / 2; i++) @@ -82,7 +82,7 @@ private void test173() throws Exception { - SecureRandom random = new FixedSecureRandom(Hex.decode("0000137449348C1249971759D99C252FFE1E14D8B31F")); + SecureRandom random = new TestRandomData(Hex.decode("0000137449348C1249971759D99C252FFE1E14D8B31F")); byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8"); for (int i = 0; i < hash.length / 2; i++) @@ -130,7 +130,7 @@ private void test283() throws Exception { - SecureRandom random = new FixedSecureRandom(Hex.decode("00000000245383CB3AD41BF30F5F7E8FBA858509B2D5558C92D539A6D994BFA98BC6940E")); + SecureRandom random = new TestRandomData(Hex.decode("00000000245383CB3AD41BF30F5F7E8FBA858509B2D5558C92D539A6D994BFA98BC6940E")); byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8"); for (int i = 0; i < hash.length / 2; i++) @@ -178,7 +178,7 @@ private void test431() throws Exception { - SecureRandom random = new FixedSecureRandom(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457")); + SecureRandom random = new TestRandomData(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457")); byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8"); for (int i = 0; i < hash.length / 2; i++) @@ -225,7 +225,7 @@ private void testTruncation() { - SecureRandom random = new FixedSecureRandom(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457")); + SecureRandom random = new TestRandomData(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457")); // use extra long "hash" with set bits... byte[] hash = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/EAXTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/EAXTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/EAXTest.java 2014-03-10 20:28:47.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/EAXTest.java 2016-11-07 00:29:38.000000000 +0000 @@ -4,7 +4,6 @@ import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.AESEngine; -import org.bouncycastle.crypto.engines.AESFastEngine; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.modes.EAXBlockCipher; import org.bouncycastle.crypto.params.AEADParameters; @@ -118,7 +117,7 @@ checkVectors(10, K10, 128, N10, A10, P10, T10, C10); checkVectors(11, K11, 32, N11, A11, P11, T11, C11); - EAXBlockCipher eax = new EAXBlockCipher(new AESFastEngine()); + EAXBlockCipher eax = new EAXBlockCipher(new AESEngine()); ivParamTest(1, eax, K1, N1); // @@ -195,8 +194,8 @@ byte[] c) throws InvalidCipherTextException { - EAXBlockCipher encEax = new EAXBlockCipher(new AESFastEngine()); - EAXBlockCipher decEax = new EAXBlockCipher(new AESFastEngine()); + EAXBlockCipher encEax = new EAXBlockCipher(new AESEngine()); + EAXBlockCipher decEax = new EAXBlockCipher(new AESEngine()); AEADParameters parameters = new AEADParameters(new KeyParameter(k), macSize, n, a); encEax.init(true, parameters); @@ -326,7 +325,7 @@ srng.nextBytes(datIn); srng.nextBytes(key); - AESFastEngine engine = new AESFastEngine(); + AESEngine engine = new AESEngine(); KeyParameter sessKey = new KeyParameter(key); EAXBlockCipher eaxCipher = new EAXBlockCipher(engine); diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/ECGOST3410Test.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/ECGOST3410Test.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/ECGOST3410Test.java 2013-12-29 23:00:07.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/ECGOST3410Test.java 2016-09-29 23:44:54.000000000 +0000 @@ -15,8 +15,8 @@ import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomData; /** * ECGOST3410 tests are taken from GOST R 34.10-2001. @@ -34,7 +34,7 @@ byte[] kData = new BigInteger("53854137677348463731403841147996619241504003434302020712960838528893196233395").toByteArray(); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomData(kData); private void ecGOST3410_TEST() { diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/ECNRTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/ECNRTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/ECNRTest.java 2013-12-29 23:00:07.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/ECNRTest.java 2016-09-29 23:44:54.000000000 +0000 @@ -12,8 +12,8 @@ import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.util.BigIntegers; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomBigInteger; /** * ECNR tests. @@ -29,7 +29,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); - SecureRandom k = new FixedSecureRandom(true, kData); + SecureRandom k = new TestRandomBigInteger(kData); private void ecNR239bitPrime() { diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/ECTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/ECTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/ECTest.java 2016-04-25 01:32:19.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/ECTest.java 2016-09-29 23:44:54.000000000 +0000 @@ -30,8 +30,8 @@ import org.bouncycastle.util.BigIntegers; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomBigInteger; /** * ECDSA tests are taken from X9.62. @@ -51,7 +51,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("6140507067065001063065065565667405560006161556565665656654")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); @@ -144,7 +144,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); - SecureRandom k = new FixedSecureRandom(true, kData); + SecureRandom k = new TestRandomBigInteger(kData); BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"); @@ -210,7 +210,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("1542725565216523985789236956265265265235675811949404040041")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); BigInteger n = new BigInteger("1569275433846670190958947355803350458831205595451630533029"); BigInteger h = BigInteger.valueOf(2); @@ -278,7 +278,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); BigInteger n = new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"); BigInteger h = BigInteger.valueOf(4); @@ -341,7 +341,7 @@ ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( new BigInteger("6081831502424510080126737029209236539191290354021104541805484120491"), // d params); - SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601"))); + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601"))); byte[] M = Hex.decode("8797A3C693CC292441039A4E6BAB7387F3B4F2A63D00ED384B378C79"); @@ -387,7 +387,7 @@ ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( new BigInteger("BE6F6E91FE96840A6518B56F3FE21689903A64FA729057AB872A9F51", 16), // d params); - SecureRandom k = new FixedSecureRandom(Hex.decode("00c39beac93db21c3266084429eb9b846b787c094f23a4de66447efbb3")); + SecureRandom k = new TestRandomBigInteger(Hex.decode("00c39beac93db21c3266084429eb9b846b787c094f23a4de66447efbb3")); byte[] M = Hex.decode("E5D5A7ADF73C5476FAEE93A2C76CE94DC0557DB04CDC189504779117920B896D"); @@ -434,7 +434,7 @@ ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( new BigInteger("20186677036482506117540275567393538695075300175221296989956723148347484984008"), // d params); - SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); @@ -480,7 +480,7 @@ ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( new BigInteger("20186677036482506117540275567393538695075300175221296989956723148347484984008"), // d params); - SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); @@ -534,7 +534,7 @@ ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( new BigInteger("6081831502424510080126737029209236539191290354021104541805484120491"), // d params); - SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601"))); + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601"))); byte[] M = Hex.decode("8797A3C693CC292441039A4E6BAB7387F3B4F2A63D00ED384B378C79FF"); @@ -581,7 +581,7 @@ ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( new BigInteger("617573726813476282316253885608633222275541026607493641741273231656161177732180358888434629562647985511298272498852936680947729040673640492310550142822667389"), // d params); - SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("6806532878215503520845109818432174847616958675335397773700324097584974639728725689481598054743894544060040710846048585856076812050552869216017728862957612913"))); + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("6806532878215503520845109818432174847616958675335397773700324097584974639728725689481598054743894544060040710846048585856076812050552869216017728862957612913"))); byte[] M = Hex.decode("6893B64BD3A9615C39C3E62DDD269C2BAAF1D85915526083183CE14C2E883B48B193607C1ED871852C9DF9C3147B574DC1526C55DE1FE263A676346A20028A66"); @@ -630,7 +630,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); BigInteger n = new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"); BigInteger h = BigInteger.valueOf(4); diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/GCMTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/GCMTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/GCMTest.java 2014-07-09 23:52:49.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/GCMTest.java 2016-11-07 00:29:38.000000000 +0000 @@ -4,7 +4,7 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.engines.AESFastEngine; +import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.engines.DESEngine; import org.bouncycastle.crypto.modes.GCMBlockCipher; import org.bouncycastle.crypto.modes.gcm.BasicGCMMultiplier; @@ -309,7 +309,7 @@ protected BlockCipher createAESEngine() { - return new AESFastEngine(); + return new AESEngine(); } private void testExceptions() throws InvalidCipherTextException @@ -338,12 +338,23 @@ // expected } - AEADTestUtil.testReset(this, new GCMBlockCipher(createAESEngine()), new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16])); + try + { + AEADTestUtil.testReset(this, new GCMBlockCipher(createAESEngine()), new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16])); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + + } + AEADTestUtil.testTampering(this, gcm, new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16])); - AEADTestUtil.testOutputSizes(this, new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter( - new byte[16]), 128, new byte[16])); - AEADTestUtil.testBufferSizeChecks(this, new GCMBlockCipher(createAESEngine()), new AEADParameters( - new KeyParameter(new byte[16]), 128, new byte[16])); + // TODO: should probably come up with varients of these that don't trigger reuse exception +// AEADTestUtil.testOutputSizes(this, new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter( +// new byte[16]), 128, new byte[16])); +// AEADTestUtil.testBufferSizeChecks(this, new GCMBlockCipher(createAESEngine()), new AEADParameters( +// new KeyParameter(new byte[16]), 128, new byte[16])); } private void runTestCase(String[] testVector) @@ -422,9 +433,16 @@ // Key reuse AEADParameters keyReuseParams = AEADTestUtil.reuseKey(parameters); - encCipher.init(true, keyReuseParams); - decCipher.init(false, keyReuseParams); - checkTestCase(encCipher, decCipher, testName + " (key reuse)", SA, P, C, T); + + try + { + encCipher.init(true, keyReuseParams); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isTrue("wrong message", "cannot reuse nonce for GCM encryption".equals(e.getMessage())); + } } private GCMBlockCipher initCipher(GCMMultiplier m, boolean forEncryption, AEADParameters parameters) diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/GMacTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/GMacTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/GMacTest.java 2014-06-21 07:05:05.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/GMacTest.java 2016-11-07 00:29:38.000000000 +0000 @@ -2,7 +2,7 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.Mac; -import org.bouncycastle.crypto.engines.AESFastEngine; +import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.macs.GMac; import org.bouncycastle.crypto.modes.GCMBlockCipher; import org.bouncycastle.crypto.params.KeyParameter; @@ -104,7 +104,7 @@ { TestCase testCase = TEST_VECTORS[i]; - Mac mac = new GMac(new GCMBlockCipher(new AESFastEngine()), testCase.getTag().length * 8); + Mac mac = new GMac(new GCMBlockCipher(new AESEngine()), testCase.getTag().length * 8); CipherParameters key = new KeyParameter(testCase.getKey()); mac.init(new ParametersWithIV(key, testCase.getIv())); @@ -122,7 +122,7 @@ { try { - GMac mac = new GMac(new GCMBlockCipher(new AESFastEngine()), size); + GMac mac = new GMac(new GCMBlockCipher(new AESEngine()), size); mac.init(new ParametersWithIV(null, new byte[16])); fail("Expected failure for illegal mac size " + size); } diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/GOST3410Test.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/GOST3410Test.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/GOST3410Test.java 2015-04-26 02:19:07.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/GOST3410Test.java 2016-09-28 01:07:47.000000000 +0000 @@ -1,5 +1,8 @@ package org.bouncycastle.crypto.test; +import java.math.BigInteger; +import java.security.SecureRandom; + import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.generators.GOST3410KeyPairGenerator; import org.bouncycastle.crypto.generators.GOST3410ParametersGenerator; @@ -13,11 +16,9 @@ import org.bouncycastle.util.test.NumberParsing; import org.bouncycastle.util.test.SimpleTestResult; import org.bouncycastle.util.test.Test; +import org.bouncycastle.util.test.TestRandomData; import org.bouncycastle.util.test.TestResult; -import java.math.BigInteger; -import java.security.SecureRandom; - public class GOST3410Test implements Test { @@ -38,9 +39,10 @@ return "GOST3410-TEST1-512"; } - FixedSecureRandom init_random = new FixedSecureRandom(new byte[][] { Hex.decode("00005EC900007341"), zeroTwo(64) }); - FixedSecureRandom random = new FixedSecureRandom(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A")); - FixedSecureRandom keyRandom = new FixedSecureRandom(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046")); + FixedSecureRandom init_random = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(Hex.decode("00005EC900007341")), new FixedSecureRandom.Data(zeroTwo(64)) }); + FixedSecureRandom random = new TestRandomData(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A")); + FixedSecureRandom keyRandom = new TestRandomData(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046")); BigInteger pValue = new BigInteger("EE8172AE8996608FB69359B89EB82A69854510E2977A4D63BC97322CE5DC3386EA0A12B343E9190F23177539845839786BB0C345D165976EF2195EC9B1C379E3", 16); BigInteger qValue = new BigInteger("98915E7EC8265EDFCDA31E88F24809DDB064BDC7285DD50D7289F0AC6F49DD2D", 16); @@ -139,9 +141,10 @@ return "GOST3410-TEST2-512"; } - FixedSecureRandom init_random = new FixedSecureRandom(new byte[][] { Hex.decode("000000003DFC46F1000000000000000D"), zeroTwo(64) }); - FixedSecureRandom random = new FixedSecureRandom(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A")); - FixedSecureRandom keyRandom = new FixedSecureRandom(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046")); + FixedSecureRandom init_random = new FixedSecureRandom( + new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(Hex.decode("000000003DFC46F1000000000000000D")), new FixedSecureRandom.Data(zeroTwo(64))}); + FixedSecureRandom random = new TestRandomData(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A")); + FixedSecureRandom keyRandom = new TestRandomData(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046")); BigInteger pValue = new BigInteger("8b08eb135af966aab39df294538580c7da26765d6d38d30cf1c06aae0d1228c3316a0e29198460fad2b19dc381c15c888c6dfd0fc2c565abb0bf1faff9518f85", 16); BigInteger qValue = new BigInteger("931a58fb6f0dcdf2fe7549bc3f19f4724b56898f7f921a076601edb18c93dc75", 16); diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/Poly1305Test.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/Poly1305Test.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/Poly1305Test.java 2016-08-12 23:06:32.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/Poly1305Test.java 2016-11-07 00:29:07.000000000 +0000 @@ -5,7 +5,7 @@ import org.bouncycastle.crypto.CipherKeyGenerator; import org.bouncycastle.crypto.KeyGenerationParameters; import org.bouncycastle.crypto.Mac; -import org.bouncycastle.crypto.engines.AESFastEngine; +import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.generators.Poly1305KeyGenerator; import org.bouncycastle.crypto.macs.Poly1305; import org.bouncycastle.crypto.params.KeyParameter; @@ -133,7 +133,7 @@ } else { - mac = new Poly1305(new AESFastEngine()); + mac = new Poly1305(new AESEngine()); mac.init(new ParametersWithIV(new KeyParameter(tc.key), tc.nonce)); } mac.update(tc.message, 0, tc.message.length); @@ -155,7 +155,7 @@ byte[] out = new byte[16]; int c = 0; - final Mac mac = new Poly1305(new AESFastEngine()); + final Mac mac = new Poly1305(new AESEngine()); for (int loop = 0; loop < 13; loop++) { len = 0; @@ -234,7 +234,7 @@ byte[] out = new byte[16]; // Generate baseline - Mac poly = new Poly1305(new AESFastEngine()); + Mac poly = new Poly1305(new AESEngine()); poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); poly.update(m, 0, m.length); @@ -280,7 +280,7 @@ gen.init(new KeyGenerationParameters(new SecureRandom(), 256)); byte[] k = gen.generateKey(); - Mac poly = new Poly1305(new AESFastEngine()); + Mac poly = new Poly1305(new AESEngine()); poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); try diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/RSABlindedTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/RSABlindedTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/RSABlindedTest.java 2007-10-22 07:51:35.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/RSABlindedTest.java 2016-08-26 03:22:56.000000000 +0000 @@ -102,22 +102,22 @@ private void testTruncatedPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block truncated"); + checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block incorrect"); } private void testDudPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "unknown block type"); + checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "block incorrect"); } private void testWrongPaddingPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block padding incorrect"); + checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block incorrect"); } private void testMissingDataPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "no data in block"); + checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "block incorrect"); } private void checkForPKCS1Exception(RSAKeyParameters pubParameters, RSAKeyParameters privParameters, byte[] inputData, String expectedMessage) diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/RSATest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/RSATest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/crypto/test/RSATest.java 2016-08-17 02:04:04.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/crypto/test/RSATest.java 2016-08-28 23:24:03.000000000 +0000 @@ -58,10 +58,11 @@ eng.init(true, privParameters); byte[] data = null; + byte[] overSized = null; try { - data = eng.processBlock(oversizedSig, 0, oversizedSig.length); + overSized = data = eng.processBlock(oversizedSig, 0, oversizedSig.length); } catch (Exception e) { @@ -74,7 +75,7 @@ try { - data = eng.processBlock(data, 0, data.length); + data = eng.processBlock(overSized, 0, overSized.length); fail("oversized signature block not recognised"); } @@ -86,43 +87,56 @@ } } + eng = new PKCS1Encoding(new RSAEngine(), Hex.decode("feedbeeffeedbeeffeedbeef")); + eng.init(false, new ParametersWithRandom(privParameters, new SecureRandom())); + + try + { + data = eng.processBlock(overSized, 0, overSized.length); + isTrue("not fallback", Arrays.areEqual(Hex.decode("feedbeeffeedbeeffeedbeef"), data)); + } + catch (InvalidCipherTextException e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + //System.setProperty(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY, "false"); - System.getProperties().put(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY, "false"); + System.getProperties().put(PKCS1Encoding.NOT_STRICT_LENGTH_ENABLED_PROPERTY, "true"); eng = new PKCS1Encoding(new RSAEngine()); eng.init(false, pubParameters); try { - data = eng.processBlock(data, 0, data.length); + data = eng.processBlock(overSized, 0, overSized.length); } catch (InvalidCipherTextException e) { fail("RSA: failed - exception " + e.toString(), e); } - System.getProperties().remove(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY); + System.getProperties().remove(PKCS1Encoding.NOT_STRICT_LENGTH_ENABLED_PROPERTY); } private void testTruncatedPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block truncated"); + checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block incorrect"); } private void testDudPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "unknown block type"); + checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "block incorrect"); } private void testWrongPaddingPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block padding incorrect"); + checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block incorrect"); } private void testMissingDataPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) { - checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "no data in block"); + checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "block incorrect"); } private void checkForPKCS1Exception(RSAKeyParameters pubParameters, RSAKeyParameters privParameters, byte[] inputData, String expectedMessage) @@ -349,20 +363,55 @@ eng.init(false, privParameters); + byte[] plainData = null; try { - data = eng.processBlock(data, 0, data.length); + plainData = eng.processBlock(data, 0, data.length); } catch (Exception e) { fail("failed - exception " + e.toString(), e); } - if (!input.equals(new String(Hex.encode(data)))) + if (!input.equals(Hex.toHexString(plainData))) { fail("failed PKCS1 public/private Test"); } + PKCS1Encoding fEng = new PKCS1Encoding(new RSAEngine(), input.length() / 2); + fEng.init(false, new ParametersWithRandom(privParameters, new SecureRandom())); + try + { + plainData = fEng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(Hex.toHexString(plainData))) + { + fail("failed PKCS1 public/private fixed Test"); + } + + fEng = new PKCS1Encoding(new RSAEngine(), input.length()); + fEng.init(false, new ParametersWithRandom(privParameters, new SecureRandom())); + try + { + data = fEng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (input.equals(Hex.toHexString(data))) + { + fail("failed to recognise incorrect plaint text length"); + } + + data = plainData; + // // PKCS1 - private encrypt, public decrypt // @@ -372,7 +421,7 @@ try { - data = eng.processBlock(data, 0, data.length); + data = eng.processBlock(plainData, 0, plainData.length); } catch (Exception e) { @@ -390,7 +439,7 @@ fail("failed - exception " + e.toString(), e); } - if (!input.equals(new String(Hex.encode(data)))) + if (!input.equals(Hex.toHexString(data))) { fail("failed PKCS1 private/public Test"); } diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java 2016-11-29 03:01:29.000000000 +0000 @@ -0,0 +1,175 @@ +package org.bouncycastle.math.ec.custom.sec.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.asn1.sec.SECObjectIdentifiers; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.ec.CustomNamedCurves; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Nat256; + +import junit.framework.TestCase; + +public class SecP256R1FieldTest extends TestCase +{ + private static final SecureRandom RANDOM = new SecureRandom(); + + private static final X9ECParameters DP = CustomNamedCurves + .getByOID(SECObjectIdentifiers.secp256r1); + private static final BigInteger Q = DP.getCurve().getField().getCharacteristic(); + + public void testMultiply1() + { + int COUNT = 1000; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateMultiplyInput_Random(); + ECFieldElement y = generateMultiplyInput_Random(); + + BigInteger X = x.toBigInteger(), Y = y.toBigInteger(); + BigInteger R = X.multiply(Y).mod(Q); + + ECFieldElement z = x.multiply(y); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + public void testMultiply2() + { + int COUNT = 100; + ECFieldElement[] inputs = new ECFieldElement[COUNT]; + BigInteger[] INPUTS = new BigInteger[COUNT]; + + for (int i = 0; i < inputs.length; ++i) + { + inputs[i] = generateMultiplyInput_Random(); + INPUTS[i] = inputs[i].toBigInteger(); + } + + for (int j = 0; j < inputs.length; ++j) + { + for (int k = 0; k < inputs.length; ++k) + { + BigInteger R = INPUTS[j].multiply(INPUTS[k]).mod(Q); + + ECFieldElement z = inputs[j].multiply(inputs[k]); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + } + + public void testSquare() + { + int COUNT = 1000; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateMultiplyInput_Random(); + + BigInteger X = x.toBigInteger(); + BigInteger R = X.multiply(X).mod(Q); + + ECFieldElement z = x.square(); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + /** + * Test multiplication with specifically selected values that triggered a bug in the modular + * reduction in OpenSSL (last affected version 0.9.8g). + * + * See "Practical realisation and elimination of an ECC-related software bug attack", B. B. + * Brumley, M. Barbarosa, D. Page, F. Vercauteren. + */ + public void testMultiply_OpenSSLBug() + { + int COUNT = 100; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateMultiplyInputA_OpenSSLBug(); + ECFieldElement y = generateMultiplyInputB_OpenSSLBug(); + + BigInteger X = x.toBigInteger(), Y = y.toBigInteger(); + BigInteger R = X.multiply(Y).mod(Q); + + ECFieldElement z = x.multiply(y); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + /** + * Test squaring with specifically selected values that triggered a bug in the modular reduction + * in OpenSSL (last affected version 0.9.8g). + * + * See "Practical realisation and elimination of an ECC-related software bug attack", B. B. + * Brumley, M. Barbarosa, D. Page, F. Vercauteren. + */ + public void testSquare_OpenSSLBug() + { + int COUNT = 100; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateSquareInput_OpenSSLBug(); + + BigInteger X = x.toBigInteger(); + BigInteger R = X.multiply(X).mod(Q); + + ECFieldElement z = x.square(); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + private ECFieldElement fe(BigInteger x) + { + return DP.getCurve().fromBigInteger(x); + } + + private ECFieldElement generateMultiplyInput_Random() + { + return fe(new BigInteger(DP.getCurve().getFieldSize() + 32, RANDOM).mod(Q)); + } + + private ECFieldElement generateMultiplyInputA_OpenSSLBug() + { + int[] x = Nat256.create(); + x[0] = RANDOM.nextInt() >>> 1; + x[4] = 3; + x[7] = -1; + + return fe(Nat256.toBigInteger(x)); + } + + private ECFieldElement generateMultiplyInputB_OpenSSLBug() + { + int[] x = Nat256.create(); + x[0] = RANDOM.nextInt() >>> 1; + x[3] = 1; + x[7] = -1; + + return fe(Nat256.toBigInteger(x)); + } + + private ECFieldElement generateSquareInput_OpenSSLBug() + { + int[] x = Nat256.create(); + x[0] = RANDOM.nextInt() >>> 1; + x[4] = 2; + x[7] = -1; + + return fe(Nat256.toBigInteger(x)); + } +} diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java 2016-11-29 03:01:29.000000000 +0000 @@ -0,0 +1,140 @@ +package org.bouncycastle.math.ec.custom.sec.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.asn1.sec.SECObjectIdentifiers; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.ec.CustomNamedCurves; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Nat; + +import junit.framework.TestCase; + +public class SecP384R1FieldTest extends TestCase +{ + private static final SecureRandom RANDOM = new SecureRandom(); + + private static final X9ECParameters DP = CustomNamedCurves + .getByOID(SECObjectIdentifiers.secp384r1); + private static final BigInteger Q = DP.getCurve().getField().getCharacteristic(); + + public void testMultiply1() + { + int COUNT = 1000; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateMultiplyInput_Random(); + ECFieldElement y = generateMultiplyInput_Random(); + + BigInteger X = x.toBigInteger(), Y = y.toBigInteger(); + BigInteger R = X.multiply(Y).mod(Q); + + ECFieldElement z = x.multiply(y); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + public void testMultiply2() + { + int COUNT = 100; + ECFieldElement[] inputs = new ECFieldElement[COUNT]; + BigInteger[] INPUTS = new BigInteger[COUNT]; + + for (int i = 0; i < inputs.length; ++i) + { + inputs[i] = generateMultiplyInput_Random(); + INPUTS[i] = inputs[i].toBigInteger(); + } + + for (int j = 0; j < inputs.length; ++j) + { + for (int k = 0; k < inputs.length; ++k) + { + BigInteger R = INPUTS[j].multiply(INPUTS[k]).mod(Q); + + ECFieldElement z = inputs[j].multiply(inputs[k]); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + } + + public void testSquare() + { + int COUNT = 1000; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateMultiplyInput_Random(); + + BigInteger X = x.toBigInteger(); + BigInteger R = X.multiply(X).mod(Q); + + ECFieldElement z = x.square(); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + public void testSquare_CarryBug() + { + int COUNT = 100; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateSquareInput_CarryBug(); + + BigInteger X = x.toBigInteger(); + BigInteger R = X.multiply(X).mod(Q); + + ECFieldElement z = x.square(); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + /* + * Based on another example input demonstrating the carry propagation bug in Nat192.square, as + * reported by Joseph Friel on dev-crypto. + */ + public void testSquare_CarryBug_Reported() + { + ECFieldElement x = fe(new BigInteger("2fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", 16)); + + BigInteger X = x.toBigInteger(); + BigInteger R = X.multiply(X).mod(Q); + + ECFieldElement z = x.square(); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + + private ECFieldElement fe(BigInteger x) + { + return DP.getCurve().fromBigInteger(x); + } + + private ECFieldElement generateMultiplyInput_Random() + { + return fe(new BigInteger(DP.getCurve().getFieldSize() + 32, RANDOM).mod(Q)); + } + + private ECFieldElement generateSquareInput_CarryBug() + { + int[] x = Nat.create(12); + x[0] = RANDOM.nextInt() >>> 1; + x[6] = 2; + x[10] = -1 << 16; + x[11] = -1; + + return fe(Nat.toBigInteger(12, x)); + } +} diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java 2015-07-30 00:17:40.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java 2016-08-29 00:27:41.000000000 +0000 @@ -26,6 +26,7 @@ suite.addTestSuite(NTRUSignatureKeyTest.class); suite.addTestSuite(NTRUSignerTest.class); suite.addTestSuite(NTRUSigningParametersTest.class); + suite.addTestSuite(AllTests.SimpleTestTest.class); return new BCTestSetup(suite); } diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java 2015-07-29 06:29:14.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java 2016-09-28 01:07:47.000000000 +0000 @@ -26,7 +26,8 @@ { byte[] keyData = Hex.decode("b5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); - SecureRandom keyRandom = new FixedSecureRandom(new byte[][]{keyData, keyData}); + SecureRandom keyRandom = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(keyData) }); public String getName() { diff -Nru bouncycastle-1.55/core/src/test/java/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java bouncycastle-1.56/core/src/test/java/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java --- bouncycastle-1.55/core/src/test/java/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java 2016-02-18 21:30:25.000000000 +0000 +++ bouncycastle-1.56/core/src/test/java/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java 2016-09-28 01:07:47.000000000 +0000 @@ -23,8 +23,8 @@ { byte[] keyData = Hex.decode("b5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); - SecureRandom keyRandom = new FixedSecureRandom(new byte[][] { keyData, keyData }); - + SecureRandom keyRandom = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(keyData) }); public String getName() { diff -Nru bouncycastle-1.55/core/src/test/jdk1.3/org/bouncycastle/crypto/test/DSATest.java bouncycastle-1.56/core/src/test/jdk1.3/org/bouncycastle/crypto/test/DSATest.java --- bouncycastle-1.55/core/src/test/jdk1.3/org/bouncycastle/crypto/test/DSATest.java 2013-05-24 06:48:30.000000000 +0000 +++ bouncycastle-1.56/core/src/test/jdk1.3/org/bouncycastle/crypto/test/DSATest.java 2016-12-19 01:43:19.000000000 +0000 @@ -3,9 +3,12 @@ import java.math.BigInteger; import java.security.SecureRandom; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.digests.SHA224Digest; import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA3Digest; import org.bouncycastle.crypto.generators.DSAKeyPairGenerator; import org.bouncycastle.crypto.generators.DSAParametersGenerator; import org.bouncycastle.crypto.params.DSAKeyGenerationParameters; @@ -15,12 +18,16 @@ import org.bouncycastle.crypto.params.DSAPublicKeyParameters; import org.bouncycastle.crypto.params.DSAValidationParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.signers.DSADigestSigner; import org.bouncycastle.crypto.signers.DSASigner; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.BigIntegers; +import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomBigInteger; +import org.bouncycastle.util.test.TestRandomData; /** * Test based on FIPS 186-2, Appendix 5, an example of DSA, and FIPS 168-3 test vectors. @@ -31,12 +38,14 @@ byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); - SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2}); + SecureRandom random = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2) }); byte[] keyData = Hex.decode("b5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); - SecureRandom keyRandom = new FixedSecureRandom(new byte[][] { keyData, keyData }); - + SecureRandom keyRandom = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(Hex.decode("01020304"))}); + BigInteger pValue = new BigInteger("8df2a494492276aa3d25759bb06869cbeac0d83afb8d0cf7cbb8324f0d7882e5d0762fc5b7210eafc2e9adac32ab7aac49693dfbf83724c2ec0736ee31c80291", 16); BigInteger qValue = new BigInteger("c773218c737ec8ee993b4f2ded30f48edace915f", 16); @@ -51,7 +60,7 @@ BigInteger s = new BigInteger("1089214853334067536215539335472893651470583479365"); DSAParametersGenerator pGen = new DSAParametersGenerator(); - pGen.init(512, 20, random); + pGen.init(512, 80, random); DSAParameters params = pGen.generateParameters(); DSAValidationParameters pValid = params.getValidationParameters(); @@ -103,6 +112,106 @@ //dsa2Test2(); //dsa2Test3(); //dsa2Test4(); + + testDSAsha3(224, new BigInteger("613202af2a7f77e02b11b5c3a5311cf6b412192bc0032aac3ec127faebfc6bd0", 16)); + testDSAsha3(256, new BigInteger("2450755c5e15a691b121bc833b97864e34a61ee025ecec89289c949c1858091e", 16)); + testDSAsha3(384, new BigInteger("7aad97c0b71bb1e1a6483b6948a03bbe952e4780b0cee699a11731f90d84ddd1", 16)); + testDSAsha3(512, new BigInteger("725ad64d923c668e64e7c3898b5efde484cab49ce7f98c2885d2a13a9e355ad4", 16)); + } + + private void testDSAsha3(int size, BigInteger s) + { + DSAParameters dsaParams = new DSAParameters( + new BigInteger( + "F56C2A7D366E3EBDEAA1891FD2A0D099" + + "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" + + "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" + + "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" + + "5909132627F51A0C866877E672E555342BDF9355347DBD43" + + "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" + + "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" + + "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" + + "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" + + "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" + + "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16), + new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16), + new BigInteger( + "8DC6CC814CAE4A1C05A3E186A6FE27EA" + + "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" + + "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" + + "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" + + "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" + + "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" + + "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" + + "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" + + "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" + + "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" + + "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16) + ); + + BigInteger x = new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16); + + BigInteger y = new BigInteger( + "2828003D7C747199143C370FDD07A286" + + "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" + + "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" + + "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" + + "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" + + "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" + + "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" + + "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" + + "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" + + "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" + + "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16); + + DSAPrivateKeyParameters priKey = new DSAPrivateKeyParameters(x, dsaParams); + SecureRandom k = new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))), + new FixedSecureRandom.Data(Hex.decode("01020304")) + }); + + byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); + + DSADigestSigner dsa = new DSADigestSigner(new DSASigner(), new SHA3Digest(size)); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + dsa.update(M, 0, M.length); + + byte[] encSig = dsa.generateSignature(); + + ASN1Sequence sig = ASN1Sequence.getInstance(encSig); + + BigInteger r = new BigInteger("4864074fe30e6601268ee663440e4d9b703f62673419864e91e9edb0338ce510", 16); + + BigInteger sigR = ASN1Integer.getInstance(sig.getObjectAt(0)).getValue(); + if (!r.equals(sigR)) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sigR.toString(16)); + } + + BigInteger sigS = ASN1Integer.getInstance(sig.getObjectAt(1)).getValue(); + if (!s.equals(sigS)) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sigS.toString(16)); + } + + // Verify the signature + DSAPublicKeyParameters pubKey = new DSAPublicKeyParameters(y, dsaParams); + + dsa.init(false, pubKey); + + dsa.update(M, 0, M.length); + + if (!dsa.verifySignature(encSig)) + { + fail("signature fails"); + } } private void dsa2Test1() @@ -111,7 +220,7 @@ DSAParametersGenerator pGen = new DSAParametersGenerator(); - pGen.init(new DSAParameterGenerationParameters(1024, 160, 10, new DSATestSecureRandom(seed))); + pGen.init(new DSAParameterGenerationParameters(1024, 160, 80, new DSATestSecureRandom(seed))); DSAParameters params = pGen.generateParameters(); @@ -156,7 +265,7 @@ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); - kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("D0EC4E50BB290A42E9E355C73D8809345DE2E139")), params)); + kpGen.init(new DSAKeyGenerationParameters(new TestRandomBigInteger("D0EC4E50BB290A42E9E355C73D8809345DE2E139", 16), params)); AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); @@ -182,7 +291,10 @@ DSASigner signer = new DSASigner(); - signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("349C55648DCF992F3F33E8026CFAC87C1D2BA075")))); + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger("349C55648DCF992F3F33E8026CFAC87C1D2BA075"), + new FixedSecureRandom.Data(Hex.decode("01020304")) }))); byte[] msg = Hex.decode("A9993E364706816ABA3E25717850C26C9CD0D89D"); @@ -213,7 +325,7 @@ DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA224Digest()); - pGen.init(new DSAParameterGenerationParameters(2048, 224, 10, new DSATestSecureRandom(seed))); + pGen.init(new DSAParameterGenerationParameters(2048, 224, 80, new DSATestSecureRandom(seed))); DSAParameters params = pGen.generateParameters(); @@ -268,7 +380,7 @@ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); - kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17")), params)); + kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17")), params)); AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); @@ -299,7 +411,11 @@ DSASigner signer = new DSASigner(); - signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("735959CC4463B8B440E407EECA8A473BF6A6D1FE657546F67D401F05")))); + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger(Hex.decode("735959CC4463B8B440E407EECA8A473BF6A6D1FE657546F67D401F05")), + new FixedSecureRandom.Data(Hex.decode("01020304")) + }))); byte[] msg = Hex.decode("23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); @@ -329,7 +445,7 @@ DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA256Digest()); - pGen.init(new DSAParameterGenerationParameters(2048, 256, 10, new DSATestSecureRandom(seed))); + pGen.init(new DSAParameterGenerationParameters(2048, 256, 80, new DSATestSecureRandom(seed))); DSAParameters params = pGen.generateParameters(); @@ -384,7 +500,7 @@ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); - kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), params)); + kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), params)); AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); @@ -415,7 +531,11 @@ DSASigner signer = new DSASigner(); - signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")))); + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), + new FixedSecureRandom.Data(Hex.decode("01020304")) + }))); byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"); @@ -445,7 +565,7 @@ DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA256Digest()); - pGen.init(new DSAParameterGenerationParameters(3072, 256, 10, new DSATestSecureRandom(seed))); + pGen.init(new DSAParameterGenerationParameters(3072, 256, 80, new DSATestSecureRandom(seed))); DSAParameters params = pGen.generateParameters(); @@ -510,7 +630,7 @@ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); - kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764")), params)); + kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764")), params)); AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); @@ -546,7 +666,10 @@ DSASigner signer = new DSASigner(); - signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("A6902C1E6E3943C5628061588A8B007BCCEA91DBF12915483F04B24AB0678BEE")))); + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] + { new FixedSecureRandom.BigInteger("A6902C1E6E3943C5628061588A8B007BCCEA91DBF12915483F04B24AB0678BEE"), + new FixedSecureRandom.Data(Hex.decode("01020304")) }))); byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"); @@ -577,7 +700,7 @@ } private class DSATestSecureRandom - extends FixedSecureRandom + extends TestRandomData { private boolean first = true; diff -Nru bouncycastle-1.55/debian/changelog bouncycastle-1.56/debian/changelog --- bouncycastle-1.55/debian/changelog 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/changelog 2017-01-06 16:34:39.000000000 +0000 @@ -1,3 +1,14 @@ +bouncycastle (1.56-1) unstable; urgency=medium + + * Team upload. + * New upstream release + - Refreshed the patches + - Updated the Maven poms + * Build with the DH sequencer instead of CDBS + * Switch to debhelper level 10 + + -- Emmanuel Bourg Fri, 06 Jan 2017 17:34:39 +0100 + bouncycastle (1.55-2) unstable; urgency=medium * Team upload. diff -Nru bouncycastle-1.55/debian/compat bouncycastle-1.56/debian/compat --- bouncycastle-1.55/debian/compat 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/compat 2017-01-06 15:03:19.000000000 +0000 @@ -1 +1 @@ -9 +10 diff -Nru bouncycastle-1.55/debian/control bouncycastle-1.56/debian/control --- bouncycastle-1.55/debian/control 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/control 2017-01-06 15:03:19.000000000 +0000 @@ -6,8 +6,7 @@ Emmanuel Bourg Build-Depends: ant, ant-optional, - cdbs (>= 0.4.27), - debhelper (>= 9), + debhelper (>= 10), default-jdk (>= 1:1.6), javahelper, junit, diff -Nru bouncycastle-1.55/debian/copyright bouncycastle-1.56/debian/copyright --- bouncycastle-1.55/debian/copyright 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/copyright 2017-01-06 15:29:36.000000000 +0000 @@ -3,7 +3,7 @@ Source: http://www.bouncycastle.org Files: * -Copyright: 2000-2015, The Legion Of The Bouncy Castle +Copyright: 2000-2016, The Legion Of The Bouncy Castle License: Expat Files: pg/src/main/java/org/bouncycastle/apache/bzip2/* @@ -20,7 +20,7 @@ 2011, James Page 2011-2012, Brian Thomason 2012, Damien Raude-Morvan - 2013-2016, Emmanuel Bourg + 2013-2017, Emmanuel Bourg 2015, Markus Koschany License: Expat diff -Nru bouncycastle-1.55/debian/libbcmail-java-doc.doc-base bouncycastle-1.56/debian/libbcmail-java-doc.doc-base --- bouncycastle-1.55/debian/libbcmail-java-doc.doc-base 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/libbcmail-java-doc.doc-base 2017-01-06 15:03:19.000000000 +0000 @@ -5,5 +5,5 @@ Section: Programming Format: HTML -Index: /usr/share/doc/libbcmail-java-doc/api/index.html -Files: /usr/share/doc/libbcmail-java-doc/api/* +Index: /usr/share/doc/libbcmail-java/api/index.html +Files: /usr/share/doc/libbcmail-java/api/* diff -Nru bouncycastle-1.55/debian/libbcmail-java-doc.install bouncycastle-1.56/debian/libbcmail-java-doc.install --- bouncycastle-1.55/debian/libbcmail-java-doc.install 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/debian/libbcmail-java-doc.install 2017-01-06 15:03:19.000000000 +0000 @@ -0,0 +1 @@ +build/artifacts/jdk1.5/javadoc/bcmail/* /usr/share/doc/libbcmail-java/api diff -Nru bouncycastle-1.55/debian/libbcmail-java.poms bouncycastle-1.56/debian/libbcmail-java.poms --- bouncycastle-1.55/debian/libbcmail-java.poms 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/libbcmail-java.poms 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -debian/poms/bcmail.pom diff -Nru bouncycastle-1.55/debian/libbcpg-java-doc.doc-base bouncycastle-1.56/debian/libbcpg-java-doc.doc-base --- bouncycastle-1.55/debian/libbcpg-java-doc.doc-base 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/libbcpg-java-doc.doc-base 2017-01-06 15:03:19.000000000 +0000 @@ -5,5 +5,5 @@ Section: Programming Format: HTML -Index: /usr/share/doc/libbcpg-java-doc/api/index.html -Files: /usr/share/doc/libbcpg-java-doc/api/* +Index: /usr/share/doc/libbcpg-java/api/index.html +Files: /usr/share/doc/libbcpg-java/api/* diff -Nru bouncycastle-1.55/debian/libbcpg-java-doc.install bouncycastle-1.56/debian/libbcpg-java-doc.install --- bouncycastle-1.55/debian/libbcpg-java-doc.install 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/debian/libbcpg-java-doc.install 2017-01-06 15:03:19.000000000 +0000 @@ -0,0 +1 @@ +build/artifacts/jdk1.5/javadoc/bcpg/* /usr/share/doc/libbcpg-java/api diff -Nru bouncycastle-1.55/debian/libbcpg-java.poms bouncycastle-1.56/debian/libbcpg-java.poms --- bouncycastle-1.55/debian/libbcpg-java.poms 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/libbcpg-java.poms 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -debian/poms/bcpg.pom diff -Nru bouncycastle-1.55/debian/libbcpkix-java-doc.doc-base bouncycastle-1.56/debian/libbcpkix-java-doc.doc-base --- bouncycastle-1.55/debian/libbcpkix-java-doc.doc-base 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/libbcpkix-java-doc.doc-base 2017-01-06 15:03:19.000000000 +0000 @@ -5,5 +5,5 @@ Section: Programming Format: HTML -Index: /usr/share/doc/libbcpkix-java-doc/api/index.html -Files: /usr/share/doc/libbcpkix-java-doc/api/* +Index: /usr/share/doc/libbcpkix-java/api/index.html +Files: /usr/share/doc/libbcpkix-java/api/* diff -Nru bouncycastle-1.55/debian/libbcpkix-java-doc.install bouncycastle-1.56/debian/libbcpkix-java-doc.install --- bouncycastle-1.55/debian/libbcpkix-java-doc.install 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/debian/libbcpkix-java-doc.install 2017-01-06 15:03:19.000000000 +0000 @@ -0,0 +1 @@ +build/artifacts/jdk1.5/javadoc/bcpkix/* /usr/share/doc/libbcpkix-java/api diff -Nru bouncycastle-1.55/debian/libbcpkix-java.poms bouncycastle-1.56/debian/libbcpkix-java.poms --- bouncycastle-1.55/debian/libbcpkix-java.poms 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/libbcpkix-java.poms 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -debian/poms/bcpkix.pom diff -Nru bouncycastle-1.55/debian/libbcprov-java-doc.doc-base bouncycastle-1.56/debian/libbcprov-java-doc.doc-base --- bouncycastle-1.55/debian/libbcprov-java-doc.doc-base 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/libbcprov-java-doc.doc-base 2017-01-06 15:03:19.000000000 +0000 @@ -5,5 +5,5 @@ Section: Programming Format: HTML -Index: /usr/share/doc/libbcprov-java-doc/api/index.html -Files: /usr/share/doc/libbcprov-java-doc/api/* +Index: /usr/share/doc/libbcprov-java/api/index.html +Files: /usr/share/doc/libbcprov-java/api/* diff -Nru bouncycastle-1.55/debian/libbcprov-java-doc.install bouncycastle-1.56/debian/libbcprov-java-doc.install --- bouncycastle-1.55/debian/libbcprov-java-doc.install 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/debian/libbcprov-java-doc.install 2017-01-06 15:03:19.000000000 +0000 @@ -0,0 +1 @@ +build/artifacts/jdk1.5/javadoc/bcprov/* /usr/share/doc/libbcprov-java/api diff -Nru bouncycastle-1.55/debian/libbcprov-java.poms bouncycastle-1.56/debian/libbcprov-java.poms --- bouncycastle-1.55/debian/libbcprov-java.poms 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/libbcprov-java.poms 2017-01-06 15:03:19.000000000 +0000 @@ -1 +1,4 @@ -debian/poms/bcprov.pom +debian/poms/bcprov.pom --has-package-version --java-lib --package=libbcprov-java --artifact=build/artifacts/jdk1.5/jars/bcprov-jdk15on-*.jar +debian/poms/bcpkix.pom --has-package-version --java-lib --package=libbcpkix-java --artifact=build/artifacts/jdk1.5/jars/bcpkix-jdk15on-*.jar +debian/poms/bcmail.pom --has-package-version --java-lib --package=libbcmail-java --artifact=build/artifacts/jdk1.5/jars/bcmail-jdk15on-*.jar +debian/poms/bcpg.pom --has-package-version --java-lib --package=libbcpg-java --artifact=build/artifacts/jdk1.5/jars/bcpg-jdk15on-*.jar diff -Nru bouncycastle-1.55/debian/orig-tar.exclude bouncycastle-1.56/debian/orig-tar.exclude --- bouncycastle-1.55/debian/orig-tar.exclude 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/orig-tar.exclude 2017-01-06 15:03:19.000000000 +0000 @@ -9,3 +9,4 @@ .gradle .gitattributes *.iml +pg/test.bak diff -Nru bouncycastle-1.55/debian/patches/fix-encoding.patch bouncycastle-1.56/debian/patches/fix-encoding.patch --- bouncycastle-1.55/debian/patches/fix-encoding.patch 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/patches/fix-encoding.patch 2017-01-06 15:26:56.000000000 +0000 @@ -12,7 +12,7 @@ --- a/ant/bc+-build.xml +++ b/ant/bc+-build.xml -@@ -100,7 +100,8 @@ +@@ -106,7 +106,8 @@ -@@ -136,7 +137,8 @@ +@@ -142,7 +143,8 @@ -@@ -211,7 +213,8 @@ +@@ -217,7 +219,8 @@ -@@ -273,7 +276,8 @@ +@@ -279,7 +282,8 @@ bcmail-jdk15on jar Bouncy Castle S/MIME API - 1.55 + 1.56 The Bouncy Castle Java S/MIME APIs for handling S/MIME protocols. This jar contains S/MIME APIs for JDK 1.5 to JDK 1.8. The APIs can be used in conjunction with a JCE/JCA provider such as the one provided with the Bouncy Castle Cryptography APIs. The JavaMail API and the Java activation framework will also be needed. http://www.bouncycastle.org/java.html @@ -33,13 +33,13 @@ org.bouncycastle bcprov-jdk15on - 1.55 + 1.56 jar org.bouncycastle bcpkix-jdk15on - 1.55 + 1.56 jar diff -Nru bouncycastle-1.55/debian/poms/bcpg.pom bouncycastle-1.56/debian/poms/bcpg.pom --- bouncycastle-1.55/debian/poms/bcpg.pom 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/poms/bcpg.pom 2016-12-23 05:30:48.000000000 +0000 @@ -5,7 +5,7 @@ bcpg-jdk15on jar Bouncy Castle OpenPGP API - 1.55 + 1.56 The Bouncy Castle Java API for handling the OpenPGP protocol. This jar contains the OpenPGP API for JDK 1.5 to JDK 1.8. The APIs can be used in conjunction with a JCE/JCA provider such as the one provided with the Bouncy Castle Cryptography APIs. http://www.bouncycastle.org/java.html @@ -38,7 +38,7 @@ org.bouncycastle bcprov-jdk15on - 1.55 + 1.56 jar diff -Nru bouncycastle-1.55/debian/poms/bcpkix.pom bouncycastle-1.56/debian/poms/bcpkix.pom --- bouncycastle-1.55/debian/poms/bcpkix.pom 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/poms/bcpkix.pom 2016-12-23 05:29:04.000000000 +0000 @@ -5,7 +5,7 @@ bcpkix-jdk15on jar Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs - 1.55 + 1.56 The Bouncy Castle Java APIs for CMS, PKCS, EAC, TSP, CMP, CRMF, OCSP, and certificate generation. This jar contains APIs for JDK 1.5 to JDK 1.8. The APIs can be used in conjunction with a JCE/JCA provider such as the one provided with the Bouncy Castle Cryptography APIs. http://www.bouncycastle.org/java.html @@ -33,7 +33,7 @@ org.bouncycastle bcprov-jdk15on - 1.55 + 1.56 jar diff -Nru bouncycastle-1.55/debian/poms/bcprov.pom bouncycastle-1.56/debian/poms/bcprov.pom --- bouncycastle-1.55/debian/poms/bcprov.pom 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/poms/bcprov.pom 2016-12-23 05:11:36.000000000 +0000 @@ -5,7 +5,7 @@ bcprov-jdk15on jar Bouncy Castle Provider - 1.55 + 1.56 The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.5 to JDK 1.8. http://www.bouncycastle.org/java.html diff -Nru bouncycastle-1.55/debian/rules bouncycastle-1.56/debian/rules --- bouncycastle-1.55/debian/rules 2016-11-23 20:46:41.000000000 +0000 +++ bouncycastle-1.56/debian/rules 2017-01-06 15:03:19.000000000 +0000 @@ -1,66 +1,32 @@ #!/usr/bin/make -f -# -*- makefile -*- - -include /usr/share/cdbs/1/class/ant.mk -include /usr/share/cdbs/1/rules/debhelper.mk UPSTREAM_VERSION = $(shell dpkg-parsechangelog | sed -rne 's,^Version: ([^-]+).*,\1,p' | sed 's/\+dfsg//') -ARTIFACTS = bcprov bcpg bcmail bcpkix -BUILD_DIR = build/artifacts/jdk1.5 -JAVA_HOME := /usr/lib/jvm/default-java -DEB_JARS := junit javax.mail -DEB_ANT_BUILDFILE := ant/jdk15+.xml -DEB_ANT_BUILD_TARGET := build-provider build -DEB_INSTALL_CHANGELOGS_ALL := docs/releasenotes.html - - -clean:: - mh_clean - rm -f stamp-* - rm -rf build - rm -f *.bpg test.* large.* secret.asc pub.asc - -# bcprov -binary-install/libbcprov-java:: build/libbcprov-java - mh_installpoms -plibbcprov-java - mh_installjar -plibbcprov-java -l debian/poms/bcprov.pom $(BUILD_DIR)/jars/bcprov-jdk15on-*.jar +export CLASSPATH=/usr/share/java/javax.mail.jar + +%: + dh $@ --buildsystem=ant --with maven-repo-helper --with javahelper + +override_dh_auto_build: + dh_auto_build -- -f ant/jdk15+.xml build-provider build + +override_dh_auto_install: + dh_auto_install dh_installdirs -plibbcprov-java etc/java/security/security.d touch debian/libbcprov-java/etc/java/security/security.d/2000-org.bouncycastle.jce.provider.BouncyCastleProvider -binary-install/libbcprov-java-doc:: - mv -i $(BUILD_DIR)/javadoc/bcprov debian/libbcprov-java-doc/usr/share/doc/libbcprov-java-doc/api -# bcmail -binary-install/libbcmail-java:: build/libbcmail-java - mh_installpoms -plibbcmail-java - mh_installjar -plibbcmail-java -l debian/poms/bcmail.pom $(BUILD_DIR)/jars/bcmail-jdk15on-*.jar - jh_classpath -plibbcmail-java -binary-install/libbcmail-java-doc:: - mv -i $(BUILD_DIR)/javadoc/bcmail debian/libbcmail-java-doc/usr/share/doc/libbcmail-java-doc/api - -# bcpg -binary-install/libbcpg-java:: build/libbcpg-java - mh_installpoms -plibbcpg-java - mh_installjar -plibbcpg-java -l debian/poms/bcpg.pom $(BUILD_DIR)/jars/bcpg-jdk15on-*.jar - jh_classpath -plibbcpg-java -binary-install/libbcpg-java-doc:: - mv -i $(BUILD_DIR)/javadoc/bcpg debian/libbcpg-java-doc/usr/share/doc/libbcpg-java-doc/api - -# bcpkix -binary-install/libbcpkix-java:: build/libbcpkix-java - mh_installpoms -plibbcpkix-java - mh_installjar -plibbcpkix-java -l debian/poms/bcpkix.pom $(BUILD_DIR)/jars/bcpkix-jdk15on-*.jar - jh_classpath -plibbcpkix-java -binary-install/libbcpkix-java-doc:: - mv -i $(BUILD_DIR)/javadoc/bcpkix debian/libbcpkix-java-doc/usr/share/doc/libbcpkix-java-doc/api +override_dh_installchangelogs: + dh_installchangelogs -- docs/releasenotes.html +override_dh_auto_clean: + dh_auto_clean -- -f ant/jdk15+.xml get-orig-pom: mkdir -p debian/poms - for pom in $(ARTIFACTS); do \ + for pom in bcprov bcpg bcmail bcpkix; do \ wget -O debian/poms/$${pom}.pom -U NoAgent-1.0 \ http://repo1.maven.org/maven2/org/bouncycastle/$${pom}-jdk15on/$(UPSTREAM_VERSION)/$${pom}-jdk15on-$(UPSTREAM_VERSION).pom ; \ done ; get-orig-source: - -uscan --download-version `echo $(DEB_UPSTREAM_VERSION) |sed -e 's/\.//g;s/\+dfsg//'` --force-download --rename + uscan --download-current-version --force-download --rename diff -Nru bouncycastle-1.55/docs/releasenotes.html bouncycastle-1.56/docs/releasenotes.html --- bouncycastle-1.55/docs/releasenotes.html 2016-08-18 00:26:37.000000000 +0000 +++ bouncycastle-1.56/docs/releasenotes.html 2016-12-23 04:32:48.000000000 +0000 @@ -23,9 +23,61 @@

2.0 Release History

2.1.1 Version

-Release: 1.55
+Release: 1.56
+Date:      2016, December 23

2.1.2 Defects Fixed

    +
  • See section 2.1.4 for Security Defects.
  • +
  • Using unknown status with the ASN.1 CertStatus primitive could result in an IllegalArgumentException on construction. This has been fixed.
  • +
  • A potentional NullPointerException in a precomputation in WNafUtil has been removed.
  • +
  • PGPUtil.getDecoderStream() would throw something other than an IOException for empty and very small data. This has been fixed. +
+

2.1.3 Additional Features and Functionality

+
    +
  • Support for the explicit setting of AlgorithmParameters has been added to the JceCMSContentEncryptorBuilder and the JceCMSMacCaculatorBuilder classes to allow configuration of the session cipher/MAC used.
  • +
  • EC, ECGOST3410, and DSTU4145 Public keys are now validated on construction in the JCA/JCE and the light weight API.
  • +
  • DSA Public keys are now validated on construction in the JCA/JCE and the light weight API.
  • +
  • Diffie-Hellman public keys are now validated where parameters allow it.
  • +
  • Some validations are now applied to RSA moduli and public exponents.
  • +
  • The ASN.1 Object Identifier cache now uses a Concurrent HashMap for additional speed.
  • +
  • AES-CCM MAC support has been added to the provider.
  • +
  • Support for ChaCha7539 (ChaCha20 as defined in RFC 7539) and Poly1305 have been added to the provider.
  • +
  • Support has been added for defining your own curves and making them available to the key generators and factories.
  • +
  • Methods have been added for specifying that a PGPPublicKey/PGPPublicKeyRing is being encoded for export and trust packets are not required.
  • +
  • Plain-ECDSA and SHA-3 support has been added to DefaultDigestAlgorithmIdentifierFinder.
  • +
  • SHA-3 support has been added to BcDefaultDigestProvider.
  • +
  • A higher level TLS API and JSSE provider have been added to the project.
  • +
+

2.1.4 Security Related Changes and CVE's Addressed by this Release

+
    +
  • It is now possible to configure the provider to only import keys for specific named curves.
  • +
  • Work has been done to improve the "constant time" behaviour of the RSA padding mechanisms.
  • +
  • The GCM ciphers in the JCE and lightweight API will now fail if an attempt is made to use them for encryption after a doFinal or without changing the IV.
  • +
  • The constructor for IESParameterSpec that allows the use of cipher without a nonce has been deleted. See also details for CVE-2016-1000344, CVE-2016-1000352.
  • +
  • Strict encoding enforcement has been introduced for ASN1Integer.
  • +
  • CVE-2016-1000338: DSA does not fully validate ASN.1 encoding of signature on verification. It is possible to inject extra elements in the sequence making up the signature and still have it validate, which in some cases may allow the introduction of "invisible" data into a signed structure.
  • +
  • CVE-2016-1000339: AESFastEngine has a side channel leak if table accesses can be observed. The use of lookup large static lookup tables in AESFastEngine means that where data accesses by the CPU can be observed, it is possible to gain information about the key used to initialize the cipher. We now recommend not using AESFastEngine where this might be a concern. The BC provider is now using AESEngine by default.
  • +
  • CVE-2016-1000340: Static ECDH vulnerable to carry propagation bug. +Carry propagation bugs in the implementation of squaring for several raw math classes have been fixed (org.bouncycastle.math.raw.Nat???). These classes are used by our custom elliptic curve implementations (org.bouncycastle.math.ec.custom.**), so there was the possibility of rare (in general usage) spurious calculations for elliptic curve scalar multiplications. Such errors would have been detected with high probability by the output validation for our scalar multipliers.
  • +
  • CVE-2016-1000341: DSA signature generation vulnerable to timing attack. Where timings can be closely observed for the generation of signatures, the lack of blinding in 1.55 or earlier, may allow an attacker to gain information about the signatures k value and ultimately the private value as well.
  • +
  • CVE-2016-1000342: ECDSA does not fully validate ASN.1 encoding of signature on verification. It is possible to inject extra elements in the sequence making up the signature and still have it validate, which in some cases may allow the introduction of "invisible" data into a signed structure.
  • +
  • CVE-2016-1000343: DSA key pair generator generates a weak private key if used with default values. If the JCA key pair generator is not explicitly initialised with DSA parameters, 1.55 and earlier generates a private value assuming a 1024 bit key size. In earlier releases this can be dealt with by explictly passing parameters to the key pair generator.
  • +
  • CVE-2016-1000344: DHIES allows the use of unsafe ECB mode. This algorithm is now removed from the provider.
  • +
  • CVE-2016-1000345: DHIES/ECIES CBC mode vulnerable to padding oracle attack. For BC 1.55 and older, in an environment where timings can be easily observed, it is possible with enough observations to identify when the decryption is failing due to padding.
  • +
  • CVE-2016-1000346: Other party DH public key not fully validated. This can cause issues as invalid keys can be used to reveal details about the other party's private key where static Diffie-Hellman is in use. As of this release the key parameters are checked on agreement calculation.
  • +
  • CVE-2016-1000352: ECIES allows the use of unsafe ECB mode. This algorithm is now removed from the provider.
  • +
+ +

2.1.5 Security Advisory

+
    +
  • We consider the carry propagation bugs fixed in this release to have been exploitable in previous releases (1.51-1.55), for static ECDH, to reveal the long-term key, per "Practical realisation and elimination of an ECC-related software bug attack", Brumley et.al.. The most common case of this would be the non-ephemeral ECDH ciphersuites in TLS. These are not enabled by default in our TLS implementations, but they can be enabled explicitly by users. We recommend that users DO NOT enable static ECDH ciphersuites for TLS.
  • +
+ +

2.2.1 Version

+Release: 1.55
+Date:      2016, August 18 +

2.2.2 Defects Fixed

+
  • Issues with cloning of blake digests with salts and personalisation strings have been fixed.
  • The JceAsymmetricValueDecryptor in the CRMF package now attempts to recognise a wider range of parameters for the key wrapping algorithm, rather than relying on a default.
  • GCM now fails if an attempt is made to go past 2^32-1 blocks.
  • @@ -45,7 +97,7 @@
  • Trying to use of non-default parameters for OAEP in CRMF would resort to the default parameter set. This has been fixed.
  • If the BC provider was not registered, creating a CertificateFactory would cause a new provider object to be created. This has been fixed.
-

2.1.3 Additional Features and Functionality

+

2.2.3 Additional Features and Functionality

  • The DANE API has been updated to reflect the latest standard changes.
  • The signature algorithm SPHINCS-256 has been added to the post-quantum provider (BCPQC). Support is in place for SHA-512 and SHA3-512 (using trees based around SHA512_256 and SHA3_256 respectively).
  • @@ -63,10 +115,10 @@
  • Additional search methods have been added to PGP public and secret key rings.
-

2.2.1 Version

+

2.3.1 Version

Release: 1.54
Date:      2015, December 29 -

2.2.2 Defects Fixed

+

2.3.2 Defects Fixed

  • Blake2b-160, Blake2b-256, Blake2b-384, and Blake2b-512 are now actually in the provider and an issue with cloning Blake2b digests has been fixed.
  • PKCS#5 Scheme 2 using DESede CBC is now supported by the PKCS#12 implementation.
  • @@ -75,7 +127,7 @@
  • It turns out, after advice one way and another that the NESSIE test vectors for Serpent are now what should be followed and that the vectors in the AES submission are regarded as an algorithm called Tnepres. The Serpent version now follows the NESSIE vectors, and the Tnepres cipher has been added to the provider and the lightweight API for compatibility.
  • Problems with DTLS record-layer version handling were resolved, making version negotiation work properly.
-

2.2.3 Additional Features and Functionality

+

2.3.3 Additional Features and Functionality

  • Camellia and SEED key wrapping are now supported for CMS key agreement
  • The BC TLS/DTLS code now includes a non-blocking API.
  • @@ -85,19 +137,19 @@
  • Support has been added to the CMS API for PKCS#7 ANY type encapsulated content where the encapsulated content is not an OCTET STRING.
  • PSSSigner in the lightweight API now supports fixed salts.
-

2.2.4 Security Advisory

+

2.3.4 Security Advisory

  • (D)TLS 1.2: Motivated by CVE-2015-7575, we have added validation that the signature algorithm received in DigitallySigned structures is actually one of those offered (in signature_algorithms extension or CertificateRequest). With our default TLS configuration, we do not believe there is an exploitable vulnerability in any earlier releases. Users that are customizing the signature_algorithms extension, or running a server supporting client authentication, are advised to double-check that they are not offering any signature algorithms involving MD5.
-

2.2.5 Notes

+

2.3.5 Notes

If you have been using Serpent, you will need to either change to Tnepres, or take into account the fact that Serpent is now byte-swapped compared to what it was before.

-

2.3.1 Version

+

2.4.1 Version

Release: 1.53
Date:      2015, October 10 -

2.3.2 Defects Fixed

+

2.4.2 Defects Fixed

  • The BC JCE cipher implementations could sometimes fail when used in conjunction with the JSSE and NIO. This has been fixed.
  • PGPPublicKey.getBitStrength() always returned 0 for EC keys. This has been fixed.
  • @@ -122,7 +174,7 @@
  • Some decidedly odd argument casting in the PKIXCertPathValidator has been fixed to throw an InvalidAlgorithmParameterException.
  • Presenting an empty array of certificates to the PKIXCertPathValidator would cause an IndexOutOfRangeException instead of a CertPathValidatorException. This has been fixed.
-

2.3.3 Additional Features and Functionality

+

2.4.3 Additional Features and Functionality

  • It is now possible to specify that an unwrapped key must be usable by a software provider in the asymmetric unwrappers for CMS.
  • A Blake2b implementation has been added to the provider and lightweight API.
  • @@ -138,15 +190,15 @@
  • The PKCS#12 key store will now garbage collect orphaned certificates on saving.
  • Caching for ASN.1 ObjectIdentifiers has been rewritten to make use of an intern method. The "usual suspects" are now interned automatically, and the cache is used by the parser. Other OIDs can be added to the cache by calling ASN1ObjectIdentifier.intern().
-

2.3.4 Notes

+

2.4.4 Notes

It turns out there was a similar, but different, issue in Crypto++ to the BC issue with ECIES. Crypto++ 6.0 now offers a corrected version of ECIES which is compatible with that which is now in BC.

-

2.4.1 Version

+

2.5.1 Version

Release: 1.52
Date:      2015, March 2 -

2.4.2 Defects Fixed

+

2.5.2 Defects Fixed

  • GenericSigner in the lightweight API would fail if the digest started with a zero byte, occasionally causing a TLS negotiation to fail. This has been fixed.
  • Some BC internal classes expected the BC provider to be accessible within the provider. This has been fixed.
  • @@ -163,7 +215,7 @@
  • A badly formed issuer in a X.509 certificate could cause a null pointer exception in X509CertificateHolder.toString(). This has been fixed.
  • CMSSignedData.verifySignatures() could fail on a correct counter signature due to a mismatch of the SID. This has been fixed.
-

2.4.3 Additional Features and Functionality

+

2.5.3 Additional Features and Functionality

  • The CMP support class CMPCertificate restricted the types of certificates that could be added. A more flexible method has been introduced to allow for other certificate types.
  • Support classes have be added for DNS-based Authentication of Named Entities (DANE) to the PKIX distribution.
  • @@ -190,15 +242,15 @@
  • CertPath validator will now make use of the issuer key identifier and the issuer name if a key identifier is available for the issuer.
  • Support for some JDK1.5+ language features has finally made its way into the repository.
-

2.4.4 Security Advisory

+

2.5.4 Security Advisory

  • The CTR DRBGs would not populate some bytes in the requested block of random bytes if the size of the block requested was not an exact multiple of the block size of the underlying cipher being used in the DRBG. If you are using the CTR DRBGs with "odd" keysizes, we strongly advise upgrading to this release, or contacting us for a work around.
-

2.5.1 Version

+

2.6.1 Version

Release: 1.51
Date:      2014, July 28 -

2.5.2 Defects Fixed

+

2.6.2 Defects Fixed

  • The AEAD GCM AlgorithmParameters object was unable to return a GCMParameterSpec object. This has been fixed.
  • Cipher.getIV() was returning null for AEAD mode ciphers. This has been fixed.
  • @@ -213,7 +265,7 @@
  • PKCS#12 files containing keys/certificates with empty attribute sets attached to them no longer cause an ArrayIndexOutOfBoundsException to be thrown.
  • Issues with certificate verification and server side DTLS/TLS 1.2 have now been fixed.
-

2.5.3 Additional Features and Functionality

+

2.6.3 Additional Features and Functionality

  • The range of key algorithm names that will be interpreted by KeyAgreement.generateSecret() has been expanded for ECDH derived algorithms in the provider. A KeyAgreement of ECDHwithSHA1KDF can now be explicitly created.
  • ECIES now supports the use of IVs with the underlying block cipher and CBC mode in both the lightweight and the JCE APIs.
  • @@ -240,16 +292,16 @@
  • Full support is now provided for client-side auth in the D/TLS server code.
  • Compatibility issues with some OSGI containers have been addressed.
-

2.5.4 Notes

+

2.6.4 Notes

  • Support for NTRUSigner has been deprecated as the algorithm has been withdrawn.
  • Some changes have affected the return values of some methods. If you are migrating from an earlier release, it is recommended to recompile before using this release.
  • There has been further clean out of deprecated methods in this release. If your code has previously been flagged as using a deprecated method you may need to change it. The OpenPGP API is the most heavily affected.
-

2.6.1 Version

+

2.7.1 Version

Release: 1.50
Date:      2013, December 3 -

2.6.2 Defects Fixed

+

2.7.2 Defects Fixed

  • The DualECSP800DRBG sometimes truncated the last block in the generated stream incorrectly. This has been fixed.
  • Keys produced from RSA certificates with specialised parameters would lose the parameter settings. This has been fixed.
  • @@ -263,7 +315,7 @@
  • Default RC2 parameters for 40 bit RC2 keys in CMSEnvelopedData were encoding incorrectly. This has been fixed.
  • In case of a long hash the DSTU4145 implementation would sometimes remove one bit too much during truncation. This has been fixed.
-

2.6.3 Additional Features and Functionality

+

2.7.3 Additional Features and Functionality

  • Additional work has been done on CMS recipient generation to simplify the generation of OAEP encrypted messages and allow for non-default parameters.
  • OCB implementation updated to account for changes in draft-irtf-cfrg-ocb-03.
  • @@ -283,7 +335,7 @@
  • The JDK 1.5+ provider will now recognise and use GCMParameterSpec if it is run in a 1.7 JVM.
  • Client side support and some server side support has been added for TLS/DTLS 1.2.
-

2.6.4 Notes

+

2.7.4 Notes

  • org.bouncycastle.crypto.DerivationFunction is now a base interface, the getDigest() method appears on DigestDerivationFunction.
  • Recent developments at NIST indicate the SHA-3 may be changed before final standardisation. Please bare this in mind if you are using it.
  • @@ -293,10 +345,10 @@
  • ECDH support for OpenPGP should still be regarded as experimental. It is still possible there will be compliance issues with other implementations.
-

2.7.1 Version

+

2.8.1 Version

Release: 1.49
Date:      2013, May 31 -

2.7.2 Defects Fixed

+

2.8.2 Defects Fixed

  • Occasional ArrayOutOfBounds exception in DSTU-4145 signature generation has been fixed.
  • The handling of escaped characters in X500 names is much improved.
  • @@ -307,7 +359,7 @@
  • PEMParser would throw a NullPointerException if it ran into explicit EC curve parameters, it would also throw an Exception if the named curve was not already defined. The parser now returns X9ECParmameters for explicit parameters and returns an ASN1ObjectIdentifier for a named curve.
  • The V2TBSCertListGenerator was adding the wrong date type for CRL invalidity date extensions. This has been fixed.
-

2.7.3 Additional Features and Functionality

+

2.8.3 Additional Features and Functionality

  • A SecretKeyFactory has been added that enables use of PBKDF2WithHmacSHA.
  • Support has been added to PKCS12 KeyStores and PfxPdu to handle PKCS#5 encrypted private keys.
  • @@ -336,16 +388,16 @@
  • A basic commitment package has been introduced into the lightweight API containing a digest based commitment scheme.
  • It is now possible to set the NotAfter and NotBefore date in the CRMF CertificateRequestMessageBuilder class.
-

2.7.4 Notes

+

2.8.4 Notes

  • The NTRU implementation has been moved into the org.bouncycastle.pqc package hierarchy.
  • The change to PEMParser to support explicit EC curves is not backward compatible. If you run into a named curve you need to use org.bouncycastle.asn1.x9.ECNamedCurveTable.getByOID() to look the curve up if required.
-

2.8.1 Version

+

2.9.1 Version

Release: 1.48
Date:      2013, February 10 -

2.8.2 Defects Fixed

+

2.9.2 Defects Fixed

  • Occasional key compatibility issues in IES due to variable length keys have been fixed.
  • PEMWriter now recognises the new PKCS10CertificationRequest object.
  • @@ -357,7 +409,7 @@
  • A regression in 1.47 which prevented key wrapping with regular symmetric PBE algorihtms has been fixed.
-

2.8.3 Additional Features and Functionality

+

2.9.3 Additional Features and Functionality

  • IES now supports auto generation of ephemeral keys in both the JCE and the lightweight APIs.
  • A new class PEMParser has been added to return the new CertificateHolder and Request objects introduced recently.
  • @@ -372,10 +424,10 @@
  • T61String now uses UTF-8 encoding by default rather than a simple 8 bit transform.
-

2.9.1 Version

+

2.10.1 Version

Release: 1.47
Date:      2012, March 30 -

2.9.2 Defects Fixed

+

2.10.2 Defects Fixed

  • OpenPGP ID based certifications now support UTF-8. Note: this may mean that some old certifications no longer validate - if this happens a retry can be added using by converting the ID using Strings.fromByteArray(Strings.toByteArray(id)) - this will strip out the top byte in each character.
  • IPv4/IPv6 parsing in CIDR no longer assumes octet boundaries on a mask.
  • @@ -392,7 +444,7 @@
  • Check of DH parameter L could reject some valid keys. This is now fixed.
-

2.9.3 Additional Features and Functionality

+

2.10.3 Additional Features and Functionality

  • Support is now provided via the RepeatedKey class to enable IV only re-initialisation in the JCE layer. The same effect can be acheived in the light weight API by using null as the key parameter when creating a ParametersWithIV object.
  • CRMF now supports empty poposkInput.
  • @@ -412,15 +464,15 @@
  • The J2ME lcrypto release now includes higher level classes for handling PKCS, CMS, CRMF, CMP, EAC, OpenPGP, and certificate generation.
-

2.9.4 Other notes

+

2.10.4 Other notes

Okay, so we have had to do another release. The issue we have run into is that we probably didn't go far enough in 1.46, but we are now confident that moving from this release to 2.0 should be largely just getting rid of deprecated methods. While this release does change a lot it is relatively straight forward to do a port and we have a porting guide which explains the important ones. The area there has been the most change in is the ASN.1 library which was in bad need of a rewrite after 10 years of patching. On the bright side the rewrite did allow us to eliminate a few problems and bugs in the ASN.1 library, so we have some hope anyone porting to it will also have similar benefits. As with 1.46 the other point of emphasis has been making sure interface support is available for operations across the major APIs, so the lightweight API or some local role your own methods can be used instead for doing encryption and signing.

-

2.10.1 Version

+

2.11.1 Version

Release: 1.46
Date:      2011, February 23 -

2.10.2 Defects Fixed

+

2.11.2 Defects Fixed

  • An edge condition in ECDSA which could result in an invalid signature has been fixed.
  • Exhaustive testing has been performed on the ASN.1 parser, eliminating another potential OutOfMemoryException and several escaping run time exceptions.
  • @@ -429,7 +481,7 @@
  • DERGeneralizedTime.getDate() would produce incorrect results for fractional seconds. This has been fixed.
  • PSSSigner would produce incorrect results if the MGF digest and content digest were not the same. This has been fixed.
-

2.10.3 Additional Features and Functionality

+

2.11.3 Additional Features and Functionality

  • A null genTime can be passed to TimeStampResponseGenerator.generate() to generate timeNotAvailable error responses.
  • Support has been added for reading and writing of openssl PKCS#8 encrypted keys.
  • @@ -446,7 +498,7 @@
  • PGP public subkeys can now be separately decoded and encoded.
  • An IV can now be passed to an ISO9797Alg3Mac.
-

2.10.4 Other notes

+

2.11.4 Other notes

Baring security patches we expect 1.46 will be the last of the 1.* releases. The next release of BC will be version 2.0. For this reason a lot of things in 1.46 that relate to CMS have been deprecated and @@ -464,7 +516,7 @@

  • The org.bouncycastle.cms.RecipientId class now has a collection of subclasses to allow for more specific recipient matching. If you are creating your own recipient ids you should use the constructors for the subclasses rather than relying on the set methods inherited from X509CertSelector. The dependencies on X509CertSelector and CertStore will be removed from the version 2 CMS API.
  • -

    2.11.1 Version

    +

    2.12.1 Version

    Release: 1.45
    Date:      2010, January 12

    2.10.2 Defects Fixed

    @@ -474,7 +526,7 @@
  • The provider now uses a privileged block for initialisation.
  • JCE/JCA EC keys are now serialisable.
  • -

    2.11.3 Additional Features and Functionality

    +

    2.12.3 Additional Features and Functionality

    • Support for EC MQV has been added to the light weight API, provider, and the CMS/SMIME library.
    @@ -483,10 +535,10 @@
  • This version of the provider has been specifically reviewed to eliminate possible timing attacks on algorithms such as GCM and CCM mode.
  • -

    2.12.1 Version

    +

    2.13.1 Version

    Release: 1.44
    Date:      2009, October 9 -

    2.12.2 Defects Fixed

    +

    2.13.2 Defects Fixed

    • The reset() method in BufferedAsymmetricBlockCipher is now fully clearing the buffer.
    • Use of ImplicitlyCA with KeyFactory and Sun keyspec no longer causes NullPointerException.
    • @@ -502,7 +554,7 @@
    • PKIXCertPathReviewer.getTrustAnchor() could occasionally cause a null pointer exception or an exception due to conflicting trust anchors. This has been fixed.
    • Handling of explicit CommandMap objects with the generation of S/MIME messages has been improved.
    -

    2.12.3 Additional Features and Functionality

    +

    2.13.3 Additional Features and Functionality

    • PEMReader/PEMWriter now support encrypted EC keys.
    • BC generated EC private keys now include optional fields required by OpenSSL.
    • @@ -518,24 +570,24 @@
    • Support for raw signatures has been extended to RSA and RSA-PSS in the provider. RSA support can be used in CMSSignedDataStreamGenerator to support signatures without signed attributes.
    -

    2.13.1 Version

    +

    2.14.1 Version

    Release: 1.43
    Date:      2009, April 13 -

    2.13.2 Defects Fixed

    +

    2.14.2 Defects Fixed

    • Multiple countersignature attributes are now correctly collected.
    • Two bugs in HC-128 and HC-256 related to sign extension and byte swapping have been fixed. The implementations now pass the latest ecrypt vector tests.
    • X509Name.hashCode() is now consistent with equals.
    -

    2.13.3 Security Advisory

    +

    2.14.3 Security Advisory

    • The effect of the sign extension bug was to decrease the key space the HC-128 and HC-256 ciphers were operating in and the byte swapping inverted every 32 bits of the generated stream. If you are using either HC-128 or HC-256 you must upgrade to this release.
    -

    2.14.1 Version

    +

    2.15.1 Version

    Release: 1.42
    Date:      2009, March 16 -

    2.14.2 Defects Fixed

    +

    2.15.2 Defects Fixed

    • A NullPointer exception which could be result from generating a diffie-hellman key has been fixed.
    • CertPath validation could occasionally mistakenly identify a delta CRL. This has been fixed.
    • @@ -548,7 +600,7 @@
    • Multiplication by negative powers of two is fixed in BigInteger.
    • OptionalValidity now encodes correctly.
    -

    2.14.3 Additional Features and Functionality

    +

    2.15.3 Additional Features and Functionality

    • Support for NONEwithECDSA has been added.
    • Support for Grainv1 and Grain128 has been added.
    • @@ -559,10 +611,10 @@
    • Support for the SRP-6a protocol has been added to the lightweight API.
    -

    2.15.1 Version

    +

    2.16.1 Version

    Release: 1.41
    Date:      2008, October 1 -

    2.15.2 Defects Fixed

    +

    2.16.2 Defects Fixed

    • The GeneralName String constructor now supports IPv4 and IPv6 address parsing.
    • An issue with nested-multiparts with postamble for S/MIME that was causing signatures to fail verification has been fixed.
    • @@ -573,7 +625,7 @@
    • Standard name "DiffieHellman" is now supported in the provider.
    • Better support for equality tests for '#' encoded entries has been added to X509Name.
    -

    2.15.3 Additional Features and Functionality

    +

    2.16.3 Additional Features and Functionality

    • Camellia is now 12.5% faster than previously.
    • A smaller version (around 8k compiled) of Camellia, CamelliaLightEngine has also been added.
    • @@ -584,10 +636,10 @@
    • Support for reading and extracting personalised certificates in PGP Secret Key rings has been added.
    -

    2.16.1 Version

    +

    2.17.1 Version

    Release: 1.40
    Date:      2008, July 12 -

    2.16.2 Defects Fixed

    +

    2.17.2 Defects Fixed

    • EAX mode ciphers were not resetting correctly after a doFinal/reset. This has been fixed.
    • The SMIME API was failing to verify doubly nested multipart objects in signatures correctly. This has been fixed.
    • @@ -603,7 +655,7 @@
    • The '+' character can now be escaped or quoted in the constructor for X509Name, X509Prinicipal.
    • Fix to regression from 1.38: PKIXCertPathValidatorResult.getPublicKey was returning the wrong public key when the BC certificate path validator was used.
    -

    2.16.3 Additional Features and Functionality

    +

    2.17.3 Additional Features and Functionality

    • Galois/Counter Mode (GCM) has been added to the lightweight API and the JCE provider.
    • SignedPublicKeyAndChallenge and PKCS10CertificationRequest can now take null providers if you need to fall back to the default provider mechanism.
    • @@ -611,15 +663,15 @@
    • Unnecessary local ID attributes on certificates in PKCS12 files are now automatically removed.
    • The PKCS12 store types PKCS12-3DES-3DES and PKCS12-DEF-3DES-3DES have been added to support generation of PKCS12 files with both certificates and keys protected by 3DES.
    -

    2.16.4 Additional Notes

    +

    2.17.4 Additional Notes

    • Due to problems for some users caused by the presence of the IDEA algorithm, an implementation is no longer included in the default signed jars. Only the providers of the form bcprov-ext-*-*.jar now include IDEA.
    -

    2.17.1 Version

    +

    2.18.1 Version

    Release: 1.39
    Date:      2008, March 29 -

    2.17.2 Defects Fixed

    +

    2.18.2 Defects Fixed

    • A bug causing the odd NullPointerException has been removed from the LocalizedMessage class.
    • IV handling in CMS for the SEED and Camellia was incorrect. This has been fixed.
    • @@ -633,7 +685,7 @@
    • A decoding issue with a mis-identified tagged object in CertRepMessage has been fixed.
    • \# is now properly recognised in the X509Name class.
    -

    2.17.3 Additional Features and Functionality

    +

    2.18.3 Additional Features and Functionality

    • Certifications associated with user attributes can now be created, verified and removed in OpenPGP.
    • API support now exists for CMS countersignature reading and production.
    • @@ -647,10 +699,10 @@
    • The ProofOfPossession class now better supports the underlying ASN.1 structure.
    • Support has been added to the provider for the VMPC MAC.
    -

    2.18.1 Version

    +

    2.19.1 Version

    Release: 1.38
    Date:      2007, November 7 -

    2.18.2 Defects Fixed

    +

    2.19.2 Defects Fixed

    • SMIME signatures containing non-standard quote-printable data could be altered by SMIME encryption. This has been fixed.
    • CMS signatures that do not use signed attributes were vulnerable to one of Bleichenbacher's RSA signature forgery attacks. This has been fixed.
    • @@ -664,7 +716,7 @@
    • Overwriting entities in a PKCS#12 file was not fully compliant with the JavaDoc for KeyStore. This has been fixed.
    • TlsInputStream.read() could appear to return end of file when end of file had not been reached. This has been fixed.
    -

    2.18.3 Additional Features and Functionality

    +

    2.19.3 Additional Features and Functionality

    • Buffering in the streaming CMS has been reworked. Throughput is now usually higher and the behaviour is more predictable.
    • It's now possible to pass a table of hashes to a CMS detached signature rather than having to always pass the data.
    • @@ -675,10 +727,10 @@
    • CertPathReviewer has better handling for problem trust anchors.
    • Base64 encoder now does initial size calculations to try to improve resource usage.
    -

    2.19.1 Version

    +

    2.20.1 Version

    Release: 1.37
    Date:      2007, June 15 -

    2.19.2 Defects Fixed

    +

    2.20.2 Defects Fixed

    • The ClearSignedFileProcessor example for OpenPGP did not take into account trailing white space in the file to be signed. This has been fixed.
    • @@ -692,7 +744,7 @@
    • The default private key length in the lightweght API for generated DiffieHellman parameters was absurdly small, this has been fixed.
    • Cipher.getParameters() for PBEwithSHAAndTwofish-CBC was returning null after intialisation. This has been fixed.
    -

    2.19.3 Additional Features and Functionality

    +

    2.20.3 Additional Features and Functionality

    • The block cipher mode CCM has been added to the provider and light weight API.
    • The block cipher mode EAX has been added to the provider and light weight API.
    • @@ -711,10 +763,10 @@
    • The JCE provider now supports RIPEMD160withECDSA.
    -

    2.20.1 Version

    +

    2.21.1 Version

    Release: 1.36
    Date:      2007, March 16 -

    2.20.2 Defects Fixed

    +

    2.21.2 Defects Fixed

    • DSA key generator now checks range and keysize.
    • Class loader issues with i18n classes should now be fixed.
    • @@ -728,7 +780,7 @@
    • Some surrogate pairs were not assembled correctly by the UTF8 decoder. This has been fixed.
    • Alias resolution in PKCS#12 is now case insensitive.
    -

    2.20.3 Additional Features and Functionality

    +

    2.21.3 Additional Features and Functionality

    • CMS/SMIME now supports basic EC KeyAgreement with X9.63.
    • CMS/SMIME now supports RFC 3211 password based encryption.
    • @@ -744,10 +796,10 @@
    • DSASigner now handles long messages. SHA2 family digest support for DSA has been added to the provider.
    -

    2.21.1 Version

    +

    2.22.1 Version

    Release: 1.35
    Date:      2006, December 16 -

    2.21.2 Defects Fixed

    +

    2.22.2 Defects Fixed

    • Test data files are no longer in the provider jars.
    • SMIMESignedParser now handles indefinite length data in SignerInfos.
    • @@ -762,7 +814,7 @@
    • The IESEngine could incorrectly encrypt data when used in block cipher mode. This has been fixed.
    • An error in the encoding of the KEKRecipientInfo has been fixed. Compatability warning: this may mean that versions of BC mail prior to 1.35 will have trouble processing KEK messages produced by 1.35 or later.
    -

    2.21.3 Additional Features and Functionality

    +

    2.22.3 Additional Features and Functionality

    • Further optimisations to elliptic curve math libraries.
    • API now incorporates a CertStore which should be suitable for use with LDAP.
    • @@ -783,10 +835,10 @@
    • PEMReader now supports OpenSSL ECDSA key pairs.
    • PGP packet streams can now be closed off using close() on the returned stream as well as closing the generator.
    -

    2.22.1 Version

    +

    2.23.1 Version

    Release: 1.34
    Date:      2006, October 2 -

    2.22.2 Defects Fixed

    +

    2.23.2 Defects Fixed

    • Endianess of integer conversion in KDF2BytesGenerator was incorrect. This has been fixed.
    • Generating critical signature subpackets in OpenPGP would result in a zero packet tag. This has been fixed. @@ -798,7 +850,7 @@
    • PGP Identity strings were only being interpreted as ASCII rather than UTF8. This has been fixed.
    • CertificateFactory.generateCRLs now returns a Collection rather than null.
    -

    2.22.3 Additional Features and Functionality

    +

    2.23.3 Additional Features and Functionality

    • An ISO18033KDFParameters class had been added to support ISO18033 KDF generators.
    • An implemention of the KDF1 bytes generator algorithm has been added. @@ -818,15 +870,15 @@
    • Performance of the prime number generation in the BigInteger library has been further improved.
    • In line with RFC 3280 section 4.1.2.4 DN's are now encoded using UTF8String by default rather than PrintableString.
    -

    2.22.4 Security Advisory

    +

    2.23.4 Security Advisory

    • If you are using public exponents with the value three you *must* upgrade to this release, otherwise it will be possible for attackers to exploit some of Bleichenbacher's RSA signature forgery attacks on your applications.
    -

    2.23.1 Version

    +

    2.24.1 Version

    Release: 1.33
    Date:      2006, May 3 -

    2.23.2 Defects Fixed

    +

    2.24.2 Defects Fixed

    • OCSPResponseData was including the default version in its encoding. This has been fixed.
    • BasicOCSPResp.getVersion() would throw a NullPointer exception if called on a default version response. This has been fixed. @@ -835,7 +887,7 @@
    • ArmoredInputStream was not closing the underlying stream on close. This has been fixed.
    • Small base64 encoded strings with embedded white space could decode incorrectly using the Base64 class. This has been fixed.
    -

    2.23.3 Additional Features and Functionality

    +

    2.24.3 Additional Features and Functionality

    • The X509V2CRLGenerator now supports adding general extensions to CRL entries.
    • A RoleSyntax implementation has been added to the x509 ASN.1 package, and the AttributeCertificateHolder class now support the IssuerSerial option. @@ -843,10 +895,10 @@
    • DERUTF8String now supports surrogate pairs.
    -

    2.24.1 Version

    +

    2.25.1 Version

    Release: 1.32
    Date:      2006, March 27 -

    2.24.2 Defects Fixed

    +

    2.25.2 Defects Fixed

    • Further work has been done on RFC 3280 compliance.
    • The ASN1Sequence constructor for SemanticsInformation would sometimes throw a ClassCastException on reconstruction an object from a byte stream. This has been fixed. @@ -863,7 +915,7 @@
    • OpenPGP clear text signatures containing '\r' as line separators were not being correctly canonicalized. This has been fixed.
    -

    2.24.3 Additional Features and Functionality

    +

    2.25.3 Additional Features and Functionality

    • The ASN.1 library now includes classes for the ICAO Electronic Passport.
    • Support has been added to CMS and S/MIME for ECDSA. @@ -872,16 +924,16 @@
    • Support has been added for repeated attributes in CMS and S/MIME messages.
    • A wider range of RSA-PSS signature types is now supported for CRL and Certificate verification.
    -

    2.24.4 Possible compatibility issue

    +

    2.25.4 Possible compatibility issue

    • Previously elliptic curve keys and points were generated with point compression enabled by default. Owing to patent issues in some jurisdictions, they are now generated with point compression disabled by default.
    -

    2.25.1 Version

    +

    2.26.1 Version

    Release: 1.31
    Date:      2005, December 29 -

    2.25.2 Defects Fixed

    +

    2.26.2 Defects Fixed

    • getCriticalExtensionOIDs on an X.509 attribute certificate was returning the non-critical set. This has been fixed.
    • Encoding uncompressed ECDSA keys could occasionally introduce an extra leading zero byte. This has been fixed. @@ -894,7 +946,7 @@ This has been fixed.
    • OIDs with extremely large components would sometimes reencode with unnecessary bytes in their encoding. The optimal DER encoding will now be produced instead.
    -

    2.25.3 Additional Features and Functionality

    +

    2.26.3 Additional Features and Functionality

    • The SMIME package now supports the large file streaming model as well.
    • Additional ASN.1 message support has been added for RFC 3739 in the org.bouncycastle.x509.qualified package. @@ -903,10 +955,10 @@
    • CertPathValidator has been updated to better support path validation as defined in RFC 3280.
    -

    2.26.1 Version

    +

    2.27.1 Version

    Release: 1.30
    Date:      2005, September 18 -

    2.26.2 Defects Fixed

    +

    2.27.2 Defects Fixed

    • Whirlpool was calculating the wrong digest for 31 byte data and could throw an exception for some other data lengths. This has been fixed.
    • AlgorithmParameters for IVs were returning a default of RAW encoding of the parameters when they should have been returning an @@ -918,7 +970,7 @@
    • KEKIdentifier would not handle OtherKeyAttribute objects correctly. This has been fixed.
    • GetCertificateChain on a PKCS12 keystore would return a single certificate chain rather than null if the alias passed in represented a certificate not a key. This has been fixed.
    -

    2.26.3 Additional Features and Functionality

    +

    2.27.3 Additional Features and Functionality

    • RSAEngine no longer assumes keys are byte aligned when checking for out of range input.
    • PGPSecretKeyRing.removeSecretKey and PGPSecretKeyRing.insertSecretKey have been added. @@ -929,10 +981,10 @@
    • Both the lightweight API and the provider now support the Camellia encryption algorithm.
    -

    2.27.1 Version

    +

    2.28.1 Version

    Release: 1.29
    Date:      2005, June 27 -

    2.27.2 Defects Fixed

    +

    2.28.2 Defects Fixed

    • HMac-SHA384 and HMac-SHA512 were not IETF compliant. This has been fixed.
    • The equals() method on ElGamalKeyParameters and DHKeyParameters in the lightweight API would sometimes @@ -943,7 +995,7 @@
    • ISO9796 signatures for full recovered messsages could incorrectly verify for similar messages in some circumstances. This has been fixed.
    • The occasional problem with decrypting PGP messages containing compressed streams now appears to be fixed.
    -

    2.27.3 Additional Features and Functionality

    +

    2.28.3 Additional Features and Functionality

    • Support has been added for the OIDs and key generation required for HMac-SHA224, HMac-SHA256, HMac-SHA384, and HMac-SHA512. @@ -951,15 +1003,15 @@
    • The provider and the lightweight API now support the GOST-28147-94 MAC algorithm.
    • Headers are now settable for PGP armored output streams.
    -

    2.27.4 Notes

    +

    2.28.4 Notes

    • The old versions of HMac-SHA384 and HMac-SHA512 can be invoked as OldHMacSHA384 and OldHMacSHA512, or by using the OldHMac class in the lightweight API.
    -

    2.28.1 Version

    +

    2.29.1 Version

    Release: 1.28
    Date:      2005, April 20 -

    2.28.2 Defects Fixed

    +

    2.29.2 Defects Fixed

    • Signatures on binary encoded S/MIME messages could fail to validate when correct. This has been fixed.
    • getExtensionValue() on CRL Entries were returning the encoding of the inner object, rather than the octet string. This has been fixed. @@ -973,7 +1025,7 @@
    • Filetype for S/MIME compressed messages was incorrect. This has been fixed.
    • BigInteger class can now create negative numbers from byte arrays.
    -

    2.28.3 Additional Features and Functionality

    +

    2.29.3 Additional Features and Functionality

    • S/MIME now does canonicalization on non-binary input for signatures.
    • Micalgs for the new SHA schemes are now supported. @@ -984,17 +1036,17 @@
    • Support has been added for the creation of ECDSA certificate requests.
    • The provider and the light weight API now support the WHIRLPOOL message digest.
    -

    2.28.4 Notes

    +

    2.29.4 Notes

    • Patches for S/MIME binary signatures and canonicalization were actually applied in 1.27, but a couple of days after the release - if the class CMSProcessableBodyPartOutbound is present in the package org.bouncycastle.mail.smime you have the patched 1.27. We would recommend upgrading to 1.28 in any case as some S/MIME 3.1 recommendations have also been introduced for header creation.
    • GOST private keys are probably not encoding correctly and can be expected to change.
    -

    2.29.1 Version

    +

    2.30.1 Version

    Release: 1.27
    Date:      2005, February 20 -

    2.29.2 Defects Fixed

    +

    2.30.2 Defects Fixed

    • Typos in the provider which pointed Signature algorithms SHA256WithRSA, SHA256WithRSAEncryption, SHA384WithRSA, SHA384WithRSAEncryption, SHA512WithRSA, and SHA512WithRSAEncryption at the PSS versions of the algorithms have been fixed. The correct names for the PSS algorithms are SHA256withRSAandMGF1, SHA384withRSAandMGF1, and SHA512withRSAandMGF1.
    • X509CertificateFactory failed under some circumstances to reset properly if the input stream being passed @@ -1008,7 +1060,7 @@
    • TSP TimeStampToken was failing to validate time stamp tokens with the issuerSerial field set in the ESSCertID structure. This has been fixed.
    • Path validation in environments with frequently updated CRLs could occasionally reject a valid path. This has been fixed.
    -

    2.29.3 Additional Features and Functionality

    +

    2.30.3 Additional Features and Functionality

    • Full support has been added for the OAEPParameterSpec class to the JDK 1.5 povider.
    • Full support has been added for the PSSParameterSpec class to the JDK 1.4 and JDK 1.5 providers. @@ -1019,7 +1071,7 @@
    • The CertPath support classes now support PKCS #7 encoding.
    • Point compression can now be turned off when encoding elliptic curve keys.
    -

    2.29.4 Changes that may affect compatibility

    +

    2.30.4 Changes that may affect compatibility

    • org.bouncycastle.jce.interfaces.ElGamalKey.getParams() has been changed to getParameters() to avoid clashes with a JCE interface with the same method signature. @@ -1028,10 +1080,10 @@
    • SHA256WithRSAEncryption, SHA384WithRSAEncryption, SHA512WithRSAEncryption now refer to their PKCS #1 V1.5 implementations. If you were using these previously you should use SHA256WithRSAAndMGF1, SHA384WithRSAAndMGF1, or SHA512WithRSAAndMGF1.
    -

    2.30.1 Version

    +

    2.31.1 Version

    Release: 1.26
    Date:      2005, January 15 -

    2.30.2 Defects Fixed

    +

    2.31.2 Defects Fixed

    • The X.509 class UserNotice assumed some of the optional fields were not optional. This has been fixed.
    • BCPGInputStream would break on input packets of 8274 bytes in length. This has been fixed. @@ -1040,7 +1092,7 @@
    • ASN1Sets now properly sort their contents when created from scratch.
    • A bug introduced in the CertPath validation in the last release which meant some certificate paths would validate if they were invalid has been fixed.
    -

    2.30.3 Additional Features and Functionality

    +

    2.31.3 Additional Features and Functionality

    • Support for JDK 1.5 naming conventions for OAEP encryption and PSS signing has been added.
    • Support for Time Stamp Protocol (RFC 3161) has been added. @@ -1050,15 +1102,15 @@
    • PBEWithMD5AndRC2, PBEWithSHA1AndRC2 now generate keys rather than exceptions.
    • The BigInteger implementation has been further optimised to take more advantage of the Montgomery number capabilities.
    -

    2.30.4 JDK 1.5 Changes

    +

    2.31.4 JDK 1.5 Changes

    • The JDK 1.5 version of the provider now supports the new Elliptic Curve classes found in the java.security packages. Note: while we have tried to preserve some backwards compatibility people using Elliptic curve are likely to find some minor code changes are required when moving code from JDK 1.4 to JDK 1.5 as the java.security APIs have changed.
    -

    2.31.1 Version

    +

    2.32.1 Version

    Release: 1.25
    Date:      2004, October 1 -

    2.31.2 Defects Fixed

    +

    2.32.2 Defects Fixed

    • In some situations OpenPGP would overread when a stream had been broken up into partial blocks. This has been fixed. @@ -1080,7 +1132,7 @@
    • Parsing a message with a zero length body with SMIMESigned would cause an exception. This has been fixed.
    • Some versions of PGP use zeros in the data stream rather than a replication of the last two bytes of the iv as specified in the RFC to determine if the correct decryption key has been found. The decryption classes will now cope with both.
    -

    2.31.3 Additional Features and Functionality

    +

    2.32.3 Additional Features and Functionality

    • Support for extracting signatures based on PGP user attributes has been added to PGPPublicKey. @@ -1099,10 +1151,10 @@
    • Trailing bit complement (TBC) padding has been added.
    • OID components of up to 2^63 bits are now supported.
    -

    2.32.1 Version

    +

    2.33.1 Version

    Release: 1.24
    Date:      2004, June 12 -

    2.32.2 Defects Fixed

    +

    2.33.2 Defects Fixed

    • OpenPGP Secret key rings now parse key rings with user attribute packets in them correctly.
    • OpenPGP Secret key rings now parse key rings with GPG comment packets in them. @@ -1119,13 +1171,13 @@
    • An encoding error introduced in 1.23 which affected generation of the KeyUsage extension has been fixed.
    -

    2.32.3 Additional Features and Functionality

    +

    2.33.3 Additional Features and Functionality

    • PKCS12 keystore now handles single key/certificate files without any attributes present.
    • Support for creation of PGPKeyRings incorporating sub keys has been added.
    • ZeroPadding for encrypting ASCII data has been added.
    -

    2.33.1 Version

    +

    2.34.1 Version

    Release: 1.23
    Date:      2004, April 10

    2.33.2 Defects Fixed

    @@ -1143,7 +1195,7 @@
  • X509Name class will now print names with nested pairs in component sets correctly.
  • RC4 now resets correctly on doFinal. -

    2.33.3 Additional Features and Functionality

    +

    2.34.3 Additional Features and Functionality

    • PGP V3 keys and V3 signature generation is now supported.
    • Collection classes have been added for representing files of PGP public and secret keys. @@ -1162,10 +1214,10 @@
    • DERGeneralizedTime getTime() method now handles a broader range of input strings.
    -

    2.34.1 Version

    +

    2.35.1 Version

    Release: 1.22
    Date:      2004, February 7 -

    2.34.2 Defects Fixed

    +

    2.35.2 Defects Fixed

    • Generating DSA signatures with PGP would cause a class cast exception, this has been fixed.
    • PGP Data in the 192 to 8383 byte length would sometimes be written with the wrong length header. This has been fixed. @@ -1175,7 +1227,7 @@
    • PSS signature verification would fail approximately 0.5 % of the time on correct signatures. This has been fixed.
    • Encoding of CRL Distribution Points now always works.
    -

    2.34.3 Additional Features and Functionality

    +

    2.35.3 Additional Features and Functionality

    • Additional methods for getting public key information have been added to the PGP package.
    • Some support for user attributes and the image attribute tag has been added. @@ -1183,10 +1235,10 @@
    • Support for ElGamal encryption/decryption has been added to the PGP package.
    -

    2.35.1 Version

    +

    2.36.1 Version

    Release: 1.21
    Date:      2003, December 6 -

    2.35.2 Defects Fixed

    +

    2.36.2 Defects Fixed

    • The CertPath validator would fail for some valid CRLs. This has been fixed.
    • AES OIDS for S/MIME were still incorrect, this has been fixed. @@ -1194,17 +1246,17 @@
    • The J2ME BigInteger class would sometimes go into an infinite loop generating prime numbers. This has been fixed.
    • DERBMPString.equals() would throw a class cast exception. This has been fixed.
    -

    2.35.3 Additional Features and Functionality

    +

    2.36.3 Additional Features and Functionality

    • PEMReader now handles public keys.
    • OpenPGP/BCPG should now handle partial input streams. Additional methods for reading subpackets off signatures.
    • The ASN.1 library now supports policy qualifiers and policy info objects.
    -

    2.36.1 Version

    +

    2.37.1 Version

    Release: 1.20
    Date:      2003, October 8 -

    2.36.2 Defects Fixed

    +

    2.37.2 Defects Fixed

    • BigInteger toString() in J2ME/JDK1.0 now produces same output as the Sun one.
    • RSA would throw a NullPointer exception with doFinal without arguments. This has been fixed. @@ -1214,7 +1266,7 @@
    • AES OIDS were incorrect, this has been fixed.
    • In some cases BC generated private keys would not work with the JSSE. This has been fixed.
    -

    2.36.3 Additional Features and Functionality

    +

    2.37.3 Additional Features and Functionality

    • Support for reading/writing OpenPGP public/private keys and OpenPGP signatures has been added.
    • Support for generating OpenPGP PBE messages and public key encrypted messages has been added. @@ -1222,10 +1274,10 @@
    • Addition of a Null block cipher to the light weight API.
    -

    2.37.1 Version

    +

    2.38.1 Version

    Release: 1.19
    Date:      2003, June 7 -

    2.37.2 Defects Fixed

    +

    2.38.2 Defects Fixed

    • The PKCS12 store would throw an exception reading PFX files that had attributes with no values. This has been fixed.
    • RSA Private Keys would not serialise if they had PKCS12 bag attributes attached to them, this has been fixed. @@ -1233,7 +1285,7 @@
    • ASN1 parser would sometimes mistake an implicit null for an implicit empty sequence. This has been fixed.
    -

    2.37.3 Additional Features and Functionality

    +

    2.38.3 Additional Features and Functionality

    • S/MIME and CMS now support the draft standard for AES encryption.
    • S/MIME and CMS now support setable key sizes for the standard algorithms. @@ -1245,10 +1297,10 @@ in order to find algorithms.
    -

    2.38.1 Version

    +

    2.39.1 Version

    Release: 1.18
    Date:      2003, February 8 -

    2.38.2 Defects Fixed

    +

    2.39.2 Defects Fixed

    • DESKeySpec.isParityAdjusted in the clean room JCE could go into an infinite loop. This has been fixed. @@ -1259,7 +1311,7 @@
    • Seeding with longs in the SecureRandom for the J2ME and JDK 1.0, only used 4 bytes of the seed value. This has been fixed.
    -

    2.38.3 Additional Features and Functionality

    +

    2.39.3 Additional Features and Functionality

    • The X.509 OID for RSA is now recognised by the provider as is the OID for RSA/OAEP.
    • Default iv's for DES are now handled correctly in CMS. @@ -1270,10 +1322,10 @@
    • Diffie-Hellman key generation is now faster in environments using the Sun BigInteger library.
    -

    2.39.1 Version

    +

    2.40.1 Version

    Release: 1.17
    Date:      2003, January 8 -

    2.39.2 Defects Fixed

    +

    2.40.2 Defects Fixed

    • Reuse of an CMSSignedObject could occasionally result in a class cast exception. This has been fixed. @@ -1284,7 +1336,7 @@
    • The DERObject constructor in OriginatorIdentifierOrKey was leaving the id field as null. This has been fixed.
    -

    2.39.2 Additional Functionality and Features

    +

    2.40.2 Additional Functionality and Features

    • RC2 now supports the full range of parameter versions and effective key sizes. @@ -1304,10 +1356,10 @@ string to OID conversion.
    -

    2.40.1 Version

    +

    2.41.1 Version

    Release: 1.16
    Date:      2002, November 30 -

    2.40.2 Defects Fixed

    +

    2.41.2 Defects Fixed

    • CRLS were only working for UTC time constructed Time objects, this has been fixed. @@ -1321,7 +1373,7 @@ to throw a NullPointerException at the wrong time.
    • Macs now clone correctly in the clean room JCE.
    -

    2.40.3 Additional Functionality and Features

    +

    2.41.3 Additional Functionality and Features

    • PGPCFB support has been added to the provider and the lightweight API.
    • There are now three versions of the AESEngine, all faster than before, @@ -1338,10 +1390,10 @@ of the Cert Path API, remove code suited to inclusion in the provider, and to support multiple recipients/signers.
    -

    2.41.1 Version

    +

    2.42.1 Version

    Release: 1.15
    Date:      2002, September 6 -

    2.41.2 Defects Fixed

    +

    2.42.2 Defects Fixed

    • The base string for the oids in asn1.x509.KeyPurposeId was incorrect. This has been fixed. @@ -1364,7 +1416,7 @@ The local name now takes precedence.
    • ReasonFlags now correctly encodes.
    -

    2.41.3 Additional Functionality and Features

    +

    2.42.3 Additional Functionality and Features

    • The PKCS12 key store now handles key bags in encryptedData bags.
    • The X509NameTokenizer now handles for '\' and '"' characters. @@ -1372,10 +1424,10 @@
    • The ASN.1 library now supports ENUMERATED, UniversalString and the X.509 library support for CRLs now includes CRLReason, and some elements of CertificatePolicies.
    • Both the provider and the lightweight library now support a basic SIC mode for block ciphers.
    -

    2.42.1 Version

    +

    2.43.1 Version

    Release: 1.14
    Date:      2002, June 17 -

    2.42.2 Defects Fixed

    +

    2.43.2 Defects Fixed

    • there was a bug in the BigInteger right shifting for > 31 bit shifts. This has been fixed. @@ -1396,7 +1448,7 @@
    • asn1.x509.ExtendedKeyUsage used to through a null pointer exception on construction. This has been fixed.
    -

    2.42.3 Additional Functionality and Features

    +

    2.43.3 Additional Functionality and Features

    • The BigInteger library now uses Montgomery numbers for modPow and is substantially faster. @@ -1409,10 +1461,10 @@
    • The X.509 certificate factory supports a wider range of encodings and object identifiers.
    -

    2.43.1 Version

    +

    2.44.1 Version

    Release: 1.13
    Date:      2002, April 19 -

    2.43.2 Defects Fixed

    +

    2.44.2 Defects Fixed

    • The TBSCertificate object in the ASN.1 library now properly implements the Time object, rather returning UTC time. @@ -1437,10 +1489,10 @@ length certificate chains for signing keys.
    -

    2.44.1 Version

    +

    2.45.1 Version

    Release: 1.12
    Date:      2002, February 8 -

    2.44.2 Defects Fixed

    +

    2.45.2 Defects Fixed

    • The ASN.1 library was unable to read an empty set object. This has been fixed.
    • Returning sets of critical and non-critical extensions on X.509 certificates could result in a null pointer exception if the certificate had no extensions. This has been fixed. @@ -1459,7 +1511,7 @@
    • the IV algorithm parameters class would improperly throw an exception on initialisation. This has been fixed.
    -

    2.44.3 Additional Functionality and Features

    +

    2.45.3 Additional Functionality and Features

    • The AESWrap ciphers will now take IV's.
    • The DES-EDEWrap algorithm described in http://www.ietf.org/internet-drafts/draft-ietf-smime-key-wrap-01.txt is now supported. @@ -1472,10 +1524,10 @@
    • Base support for CMS (RFC 2630) is now provided (see CONTRIBUTORS file for details).
    -

    2.45.1 Version

    +

    2.46.1 Version

    Release: 1.11
    Date:      2001, December 10 -

    2.45.2 Defects Fixed

    +

    2.46.2 Defects Fixed

    • X9.23 padding of MACs now works correctly with block size aligned data.
    • Loading a corrupted "UBER" key store would occasionally cause the @@ -1501,7 +1553,7 @@ extensions. This has been fixed.
    • The NetscapeCert type bits were reversed! This has been fixed.
    -

    2.45.3 Additional Functionality and Features

    +

    2.46.3 Additional Functionality and Features

    • The lightweight API and the JCE provider now support ElGamal.
    • X509Principal, and X509Name now supports the "DC" attribute and the @@ -1515,17 +1567,17 @@
    • Elliptic curve routines now handle uncompressed points as well as the compressed ones.
    -

    2.45.4 Other changes

    +

    2.46.4 Other changes

    • As the range of public key types supported has expanded the getPublicKey method on the SubjectPublicKeyInfo class is not always going to work. The more generic method getPublicKeyData has been added and getPublicKey now throws an IOException if there is a problem.
    -

    2.46.1 Version

    +

    2.47.1 Version

    Release: 1.10
    Date:      2001, October 20 -

    2.46.2 Defects Fixed

    +

    2.47.2 Defects Fixed

    • The PKCS12 Key Store now interoperates with the JDK key tool. Note: this does mean the the key name passed to the setKeyEntry calls has become significant. @@ -1533,7 +1585,7 @@ has been fixed.
    • The ASN.1 input streams now handle zero-tagged zero length objects correctly.
    -

    2.46.3 Additional Functionality and Features

    +

    2.47.3 Additional Functionality and Features

    • The JCE Provider and the lightweight API now support Serpent, CAST5, and CAST6.
    • The JCE provider and the lightweight API now has an implementation of ECIES. @@ -1542,10 +1594,10 @@
    • Further work has been done on performance - mainly in the symmetric ciphers.
    • Support for the generation of PKCS10 certification requests has been added.
    -

    2.47.1 Version

    +

    2.48.1 Version

    Release: 1.09
    Date:      2001, October 6 -

    2.47.2 Defects Fixed

    +

    2.48.2 Defects Fixed

    • failure to pass in an RC5 parameters object now results in an exception at the upper level of the JCE, rather than falling over in the lightweight @@ -1558,7 +1610,7 @@
    • In some cases the ASN.1 library wouldn't handle implicit tagging properly. This has been fixed.
    -

    2.47.3 Additional Functionality and Features

    +

    2.48.3 Additional Functionality and Features

    • Support for RC5-64 has been added to the JCE.
    • ISO9796-2 signatures have been added to the JCE and lightweight API. @@ -1582,10 +1634,10 @@ resource hungry and faster - whether it's fast enough remains to be seen!
    -

    2.48.1 Version

    +

    2.49.1 Version

    Release: 1.08
    Date:      2001, September 9 -

    2.48.2 Defects Fixed

    +

    2.49.2 Defects Fixed

    • It wasn't possible to specify an ordering for distinguished names in X509 certificates. This is now supported. @@ -1596,7 +1648,7 @@
    • The netscape certificate request class wouldn't compile under JDK 1.1. This has been fixed.
    -

    2.48.3 Additional Functionality and Features

    +

    2.49.3 Additional Functionality and Features

    • ISO 9796-1 padding is now supported with RSA in the lightweight API and the JCE. @@ -1609,10 +1661,10 @@ the collections class was not present. Thanks to a donated collections API this is fixed.
    -

    2.49.1 Version

    +

    2.50.1 Version

    Release: 1.07
    Date:      2001, July 9 -

    2.49.2 Defects Fixed

    +

    2.50.2 Defects Fixed

    • It turned out that the setOddParity method in the DESParameter class was indeed doing something odd but not what was intended. This is now @@ -1622,10 +1674,10 @@ call. If you want an example of how to deal with this as a migration issue have a look in org.bouncycastle.jce.provider.JDKKeyStore lines 201-291.
    -

    2.50.1 Version

    +

    2.51.1 Version

    Release: 1.06
    Date:      2001, July 2 -

    2.50.2 Defects Fixed

    +

    2.51.2 Defects Fixed

    • Diffie-Hellman keys are now properly serialisable as well as encodable. @@ -1648,17 +1700,17 @@ caused a NullPointer exception. This has been fixed.
    -

    2.50.3 Additional Functionality

    +

    2.51.3 Additional Functionality

    • ISO10126Padding is now recognised explicitly for block ciphers as well.
    • The Blowfish implementation is now somewhat faster.
    -

    2.51.1 Version

    +

    2.52.1 Version

    Release: 1.05
    Date:      2001, April 17 -

    2.51.2 Defects Fixed

    +

    2.52.2 Defects Fixed

    • The DESEDE key generator can now be used to generate 2-Key-DESEDE keys as well as 3-Key-DESEDE keys. @@ -1669,22 +1721,22 @@
    • The ASN.1 library was skipping explicitly tagged objects of zero length. This has been fixed.
    -

    2.51.3 Additional Functionality

    +

    2.52.3 Additional Functionality

    • There is now an org.bouncycastle.jce.netscape package which has a class in for dealing with Netscape Certificate Request objects.
    -

    2.50.4 Additional Notes

    +

    2.52.4 Additional Notes

    Concerning the PKCS12 fix: in a few cases this may cause some backward compatibility issues - if this happens to you, drop us a line at feedback-crypto@bouncycastle.org and we will help you get it sorted out. -

    2.52.1 Version

    +

    2.53.1 Version

    Release: 1.04
    Date:      2001, March 11 -

    2.52.2 Defects Fixed

    +

    2.53.2 Defects Fixed

    • Signatures generated by other providers that include optional null parameters in the AlgorithmIdentifier are now handled correctly by the @@ -1713,7 +1765,7 @@ hash table when the hash table constructor was called. This has been fixed.
    -

    2.52.3 Additional Functionality

    +

    2.53.3 Additional Functionality

    • Added Elliptic Curve DSA (X9.62) - ECDSA - to provider and lightweight library. @@ -1725,10 +1777,10 @@
    • The certificate generators now support ECDSA and DSA certs as well.
    -

    2.53.1 Version

    +

    2.54.1 Version

    Release: 1.03
    Date:      2001, January 7 -

    2.53.2 Defects Fixed

    +

    2.54.2 Defects Fixed

    • CFB and OFB modes when specified without padding would insist on input being block aligned. When specified without padding CFB and OFB now behave in a compatible @@ -1738,29 +1790,29 @@ length as the plain text.
    -

    2.54.1 Version

    +

    2.55.1 Version

    Release: 1.02
    Date:      2000, November 7 -

    2.54.2 Defects Fixed

    +

    2.55.2 Defects Fixed

    • The RSA key pair generator occasionally produced keys 1 bit under the requested size. This is now fixed.
    -

    2.55.1 Version

    +

    2.56.1 Version

    Release: 1.01
    Date:      2000, October 15 -

    2.55.2 Defects Fixed

    +

    2.56.2 Defects Fixed

    • Buffered ciphers in lightweight library were not resetting correctly on a doFinal. This has been fixed.
    -

    2.56.1 Version

    +

    2.57.1 Version

    Release: 1.00
    Date:      2000, October 13 -

    2.56.2 Defects Fixed

    +

    2.57.2 Defects Fixed

    • JDK1.2 version now works with keytool for certificate generation. @@ -1775,7 +1827,7 @@
    • Some DES PBE algorithms did not set the parity correctly in generated keys, this has been fixed.
    -

    2.56.3 Additional functionality

    +

    2.57.3 Additional functionality

    • Argument validation is much improved. diff -Nru bouncycastle-1.55/mail/build.gradle bouncycastle-1.56/mail/build.gradle --- bouncycastle-1.55/mail/build.gradle 2015-07-29 23:12:26.000000000 +0000 +++ bouncycastle-1.56/mail/build.gradle 2016-11-13 00:33:56.000000000 +0000 @@ -6,6 +6,8 @@ compile group: 'javax.mail', name: 'mail', version: '1.4' } +jar.baseName = "bcmail-jdk15on" + cobertura { coverageDirs = [ "${rootProject.projectDir}/core/build/classes/main", diff -Nru bouncycastle-1.55/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java bouncycastle-1.56/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java --- bouncycastle-1.55/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java 2015-02-15 05:46:06.000000000 +0000 +++ bouncycastle-1.56/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java 2016-10-16 20:53:49.000000000 +0000 @@ -194,14 +194,14 @@ int fromsLength = (froms != null) ? froms.length : 0; fromAddresses = new String[fromsLength + ((sender != null) ? 1 : 0)]; - for (int i = 0; i < froms.length; i++) + for (int i = 0; i < fromsLength; i++) { InternetAddress inetAddr = (InternetAddress)froms[i]; fromAddresses[i] = inetAddr.getAddress(); } if (sender != null) { - fromAddresses[froms.length] = sender.getAddress(); + fromAddresses[fromsLength] = sender.getAddress(); } // initialize results diff -Nru bouncycastle-1.55/pg/build.gradle bouncycastle-1.56/pg/build.gradle --- bouncycastle-1.55/pg/build.gradle 2015-07-29 23:12:35.000000000 +0000 +++ bouncycastle-1.56/pg/build.gradle 2016-11-13 00:33:22.000000000 +0000 @@ -3,6 +3,8 @@ compile project(':prov') } +jar.baseName = "bcpg-jdk15on" + cobertura { coverageDirs = [ "${rootProject.projectDir}/core/build/classes/main", diff -Nru bouncycastle-1.55/pg/large.txt.asc bouncycastle-1.56/pg/large.txt.asc --- bouncycastle-1.55/pg/large.txt.asc 2016-05-09 23:42:04.000000000 +0000 +++ bouncycastle-1.56/pg/large.txt.asc 2016-11-21 03:52:12.000000000 +0000 @@ -1,12 +1,12 @@ -----BEGIN PGP MESSAGE----- Version: BCPG v@RELEASE_NAME@ -hI4DTuqR+PQOiGYQAf9KbuVUMyn1N3rEUw+Rp1EBvuFwPZ37Uj3i5xx8KL5AHR+u -oi2GLnJ2k8brSfVkAsQfBL9ow5x7hcWdrvaKXs1AAf9/TKuV4pMWfmQB6FdlWSHQ -VyAcQyDLc+6jmyMkWfXSH+jrCtwaaCtgk8M4ZrkMP0ed8QxFuAj2Eo19iSvtxAfz -0pEBTLb9DSZq24H66N7pVanNiCOmW0A/EbnB7t4COiOE4Por0eYAWCylqIKHkMaA -paDr0H7GgSOlmuFN7snjXKWk6oi/bL4oakQVBMJznS5VxSlvOb6ICQ5niNKn3c/h -0e1GnZ0Wl+VCP8L8g/GeZno/ZK0zGBt2+LY3hlVP1dNM5ubJuJzGugNGYsjTUoNd -Kb1J -=//pm +hI4Dk/aUbpg4UIwQAf4sI296i/2r8KkCjGtqb6HUGA/OwlISZAwnpYartk/u8UlT +SPxzDZvJKru5Wwnv/sk769rTYpbuOXIXHRnIJJgrAfwOiHyIxYrG2WEUxdzYqVPE +zmX59S98AHw5WRca1LR9m4PQbWxtzACFWgmsvBoGlhVr88HaC7jlnh3ouf9/cThN +0o8BiN0jl1IzRzIdyfMMftogjxwenmIAJSOH3Yifuzi8PZKaxiXTTKLMtqtNhOwG +bawjWKzH2osuIKPjzSc+8Xs+b6APusuSWjqcOUfmdpPQL2ULs/+MVuZ5BTONKoIx +ynMZarg5jGC91lXL3ISeYni8jZdQ+WsZofTAjal03lq8TrI7kTyRgDZxT4TeDGRt +Mg== +=lCn2 -----END PGP MESSAGE----- Binary files /tmp/tmpowJLLf/jkZ0WCu6hH/bouncycastle-1.55/pg/large.txt.bpg and /tmp/tmpowJLLf/lAtENdT3zU/bouncycastle-1.56/pg/large.txt.bpg differ diff -Nru bouncycastle-1.55/pg/pub.asc bouncycastle-1.56/pg/pub.asc --- bouncycastle-1.55/pg/pub.asc 2016-05-09 23:42:04.000000000 +0000 +++ bouncycastle-1.56/pg/pub.asc 2016-11-21 03:52:12.000000000 +0000 @@ -1,22 +1,22 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- Version: BCPG v@RELEASE_NAME@ -mQGiBFcxIEwRBADrkF3OcSkiQOm26KWZ0zfgRMQ0JeC6vblUjiAZXU0X3s92lnLI -IzfZJdfxKFGGqN9eZh/TzCIkI5we/Q16+PAYjVQUYKQ5ft561a8wbuLZDsdKKGNA -TCYNQf+5ZiPuet+lw9NW7E62KPpqThEg/Cg/pACVRJO0zyK/2uFsOyqO4wCgkNLj -guzethsU1nBpH70yYw9q5RkD/01NbW4sdLFMYeMATZYsJFv7CAdG4uV5TyyKw0rP -+HMJcUNdMpP5tF3Tw5DXZucFxSs2tOzacddt5do//kHOBhkvM0TyQn5Ms/tlrh0l -d8aluq4RzT4yjkRZ2MMFxIE0H/eX0tpikz5vMuReU+LKEaeslRDNOvpedRCYXtcW -WOP7BACYqmBbKI1WirOc30b5oW3lMvvTvgP13Crfte+XzrCLcHDv5sjxOOMjdUEN -xEGYB0h6fOxAOAkMBDkjd885fdBjBxj0vOj0XotNj84AQ8abm3Qkmx3lmK+KjZjS -r+Aq1WmIJRvdUoL2gJDgKKJFUvbiYYXcGFmyBlwPFlRtNuheabQEdGVzdIhGBBMR -AgAGBQJXMSBMAAoJEDEDkg5B/IuiiugAnRhFtdpOb2begVXPY4IHWUaTp8QPAJ4l -j9hiwkMWlXs7chZZsHF3QB/GFbjMBFcxIEwQAgCUlP7AlfO4XuKGVCs4NvyBpd0K +mQGiBFgyb2wRBADxdL57VQ0jwUFYSEz1SUDdRHiWSUWp986TEQn4uvzKFMJKu+yx +7D78wW4iBDzh0f93ukuklni5HjnKE+lrgIWf+6pmeJXuv30OH9DCrzD+K4liQroJ +DnDI7zoxMR1JMjAC5x0sU6XwYnGpXNFxIM1xtT7fWxnvGmhg7LbswSlc6wCg67LE +xMG9eLNIPTUkB18x+L3s/qEEAPAtBnICAwHCJnUUwSIRjN6nQ5bmi4B3aKB+ddwW +tOlAvWfsYzo/rn0Dk1P11Kfyc0C1IZDnUoGRxY9QpvMncq57pP8eYyoGd0/CF29L +EO5YtXzCFHxCqYVHo74d+8+FnnNu2IRtKSz8IqBsk7XmoQueJ9Ur50Jb7IT63AF0 +k8uWA/9XEP2psS++x44L7po4628vXZ2VWcknR7qbMbNnYyKss8/xEMWV8Y6v7wbo +O75gJChv6aMRtCeZcKhWEU1tblYVXEgfmtOpqIlI33rW7xUulzJ+WbFQETRYYXxU +oOsVIZ9oRwLCq29bo4bkI27unZHsWcHgwDqZ3n7dEz0MlZt/QbQEdGVzdIhGBBMR +AgAGBQJYMm9sAAoJEFZY8Fttqb4+yrUAoIhQLeo9h2BPPL7OvVsJhQ6eN4c/AJ9z +nFD3VCU7tsHABRYjRAJWpoXd2bjMBFgyb2wQAgCUlP7AlfO4XuKGVCs4NvyBpd0K A0m0wjndOHRNSIz44x24vLfTO0GrueWjPMqRRLHO8zLJS/BXO/BHo6ypjN87Af0V PV1hcq20MEW2iujh3hBwthNwBWhtKdPXOndJGZaB7lshLJuWv9z6WyDNXj/SBEiV -1gnPm0ELeg8Syhy5pCjMAgCMDfSbdvippoN6hA18dObfCNE1CKrhNSNN3oVsMXWI -1axI1fjKHmhmSvNcfNNBgknWcdSOY1YA5N1Rs1FXyWoJiEYEGBECAAYFAlcxIEwA -CgkQMQOSDkH8i6LUQACfa+5xhiLOgvT53UEEHabJ/JxMGkgAn3jCL+OAm+kI7Vk6 -6p9fzGwKVvtv -=bCgh +1gnPm0ELeg8Syhy5pCjMAf4wK9daO5xUWu9dTFcJPc0xfhco/S51iIooAQbpqXVl +72LzLZiDN7PRqjXigEc3JsggP/vZl2ABgAXTdQAVf8xpiEYEGBECAAYFAlgyb2wA +CgkQVljwW22pvj4RCACgj4syeBD0vnh09G3ah4EazwJx2+YAoOF5uLg91Pqkl4tz +FwvusUSYl7u7 +=yTOw -----END PGP PUBLIC KEY BLOCK----- Binary files /tmp/tmpowJLLf/jkZ0WCu6hH/bouncycastle-1.55/pg/pub.bpg and /tmp/tmpowJLLf/lAtENdT3zU/bouncycastle-1.56/pg/pub.bpg differ diff -Nru bouncycastle-1.55/pg/secret.asc bouncycastle-1.56/pg/secret.asc --- bouncycastle-1.55/pg/secret.asc 2016-05-09 23:42:04.000000000 +0000 +++ bouncycastle-1.56/pg/secret.asc 2016-11-21 03:52:12.000000000 +0000 @@ -1,26 +1,26 @@ -----BEGIN PGP PRIVATE KEY BLOCK----- Version: BCPG v@RELEASE_NAME@ -lQHpBFcxIEwRBADrkF3OcSkiQOm26KWZ0zfgRMQ0JeC6vblUjiAZXU0X3s92lnLI -IzfZJdfxKFGGqN9eZh/TzCIkI5we/Q16+PAYjVQUYKQ5ft561a8wbuLZDsdKKGNA -TCYNQf+5ZiPuet+lw9NW7E62KPpqThEg/Cg/pACVRJO0zyK/2uFsOyqO4wCgkNLj -guzethsU1nBpH70yYw9q5RkD/01NbW4sdLFMYeMATZYsJFv7CAdG4uV5TyyKw0rP -+HMJcUNdMpP5tF3Tw5DXZucFxSs2tOzacddt5do//kHOBhkvM0TyQn5Ms/tlrh0l -d8aluq4RzT4yjkRZ2MMFxIE0H/eX0tpikz5vMuReU+LKEaeslRDNOvpedRCYXtcW -WOP7BACYqmBbKI1WirOc30b5oW3lMvvTvgP13Crfte+XzrCLcHDv5sjxOOMjdUEN -xEGYB0h6fOxAOAkMBDkjd885fdBjBxj0vOj0XotNj84AQ8abm3Qkmx3lmK+KjZjS -r+Aq1WmIJRvdUoL2gJDgKKJFUvbiYYXcGFmyBlwPFlRtNuheaf4JAwLnwMT+X8eQ -pmDkndH4TF/7oCoIrvMyllzXvSShB4nl/3vZoVgKph5U/Ciha6yp6iccTtV3A1Lc -B6TsJJ+OAaCv31fStAR0ZXN0iEYEExECAAYFAlcxIEwACgkQMQOSDkH8i6KK6ACd -GEW12k5vZt6BVc9jggdZRpOnxA8AniWP2GLCQxaVeztyFlmwcXdAH8YVnQE/BFcx -IEwQAgCUlP7AlfO4XuKGVCs4NvyBpd0KA0m0wjndOHRNSIz44x24vLfTO0GrueWj +lQHpBFgyb2wRBADxdL57VQ0jwUFYSEz1SUDdRHiWSUWp986TEQn4uvzKFMJKu+yx +7D78wW4iBDzh0f93ukuklni5HjnKE+lrgIWf+6pmeJXuv30OH9DCrzD+K4liQroJ +DnDI7zoxMR1JMjAC5x0sU6XwYnGpXNFxIM1xtT7fWxnvGmhg7LbswSlc6wCg67LE +xMG9eLNIPTUkB18x+L3s/qEEAPAtBnICAwHCJnUUwSIRjN6nQ5bmi4B3aKB+ddwW +tOlAvWfsYzo/rn0Dk1P11Kfyc0C1IZDnUoGRxY9QpvMncq57pP8eYyoGd0/CF29L +EO5YtXzCFHxCqYVHo74d+8+FnnNu2IRtKSz8IqBsk7XmoQueJ9Ur50Jb7IT63AF0 +k8uWA/9XEP2psS++x44L7po4628vXZ2VWcknR7qbMbNnYyKss8/xEMWV8Y6v7wbo +O75gJChv6aMRtCeZcKhWEU1tblYVXEgfmtOpqIlI33rW7xUulzJ+WbFQETRYYXxU +oOsVIZ9oRwLCq29bo4bkI27unZHsWcHgwDqZ3n7dEz0MlZt/Qf4JAwKK7NO/zqXa +3GDR95h7tB4oBFELnSlSKo41IT5n11HSI7r0U5QMLR4LenDDKei6359o0scE1Os2 +u4kM4ZR9aC2mgRhdtAR0ZXN0iEYEExECAAYFAlgyb2wACgkQVljwW22pvj7KtQCg +iFAt6j2HYE88vs69WwmFDp43hz8An3OcUPdUJTu2wcAFFiNEAlamhd3ZnQE/BFgy +b2wQAgCUlP7AlfO4XuKGVCs4NvyBpd0KA0m0wjndOHRNSIz44x24vLfTO0GrueWj PMqRRLHO8zLJS/BXO/BHo6ypjN87Af0VPV1hcq20MEW2iujh3hBwthNwBWhtKdPX -OndJGZaB7lshLJuWv9z6WyDNXj/SBEiV1gnPm0ELeg8Syhy5pCjMAgCMDfSbdvip -poN6hA18dObfCNE1CKrhNSNN3oVsMXWI1axI1fjKHmhmSvNcfNNBgknWcdSOY1YA -5N1Rs1FXyWoJ/gkDAufAxP5fx5CmYGncm37YNbQKkemL1iEnh4mlHkoOThsV/zb2 -Gem+8Vk7k1JhJwsC8oJEcQ6utuct0I8T35lPpybiOqSI/4FdUS+ZGjHl1dzUscYS -Cgho9jvN1SwZuT2dRpxS+cAQ8uwU5bxJcgmCIYhGBBgRAgAGBQJXMSBMAAoJEDED -kg5B/Iui1EAAn2vucYYizoL0+d1BBB2myfycTBpIAJ94wi/jgJvpCO1ZOuqfX8xs -Clb7bw== -=MBhx +OndJGZaB7lshLJuWv9z6WyDNXj/SBEiV1gnPm0ELeg8Syhy5pCjMAf4wK9daO5xU +Wu9dTFcJPc0xfhco/S51iIooAQbpqXVl72LzLZiDN7PRqjXigEc3JsggP/vZl2AB +gAXTdQAVf8xp/gkDAors07/OpdrcYAZ2vi2keSWS+DJcbvsuP2gcI1TAWLLZa7ln +JzRREsh9a2vg2HoatanMWhyecr+bcPeW919E+9S3UPnDGhhGjB1AAIqC+a8jtKoK +Y68iMuQ+YKu2/9nalucZQqh0LuoP66znMbeUv4hGBBgRAgAGBQJYMm9sAAoJEFZY +8Fttqb4+EQgAoI+LMngQ9L54dPRt2oeBGs8CcdvmAKDhebi4PdT6pJeLcxcL7rFE +mJe7uw== +=KWAk -----END PGP PRIVATE KEY BLOCK----- Binary files /tmp/tmpowJLLf/jkZ0WCu6hH/bouncycastle-1.55/pg/secret.bpg and /tmp/tmpowJLLf/lAtENdT3zU/bouncycastle-1.56/pg/secret.bpg differ diff -Nru bouncycastle-1.55/pg/src/main/j2me/org/bouncycastle/openpgp/PGPPublicKey.java bouncycastle-1.56/pg/src/main/j2me/org/bouncycastle/openpgp/PGPPublicKey.java --- bouncycastle-1.55/pg/src/main/j2me/org/bouncycastle/openpgp/PGPPublicKey.java 2016-08-18 00:22:14.000000000 +0000 +++ bouncycastle-1.56/pg/src/main/j2me/org/bouncycastle/openpgp/PGPPublicKey.java 2016-12-21 06:11:02.000000000 +0000 @@ -9,10 +9,12 @@ import java.util.Iterator; import java.util.List; +import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.bcpg.BCPGKey; import org.bouncycastle.bcpg.BCPGOutputStream; import org.bouncycastle.bcpg.ContainedPacket; import org.bouncycastle.bcpg.DSAPublicBCPGKey; +import org.bouncycastle.bcpg.ECPublicBCPGKey; import org.bouncycastle.bcpg.ElGamalPublicBCPGKey; import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; import org.bouncycastle.bcpg.PublicKeyPacket; @@ -81,9 +83,13 @@ { this.keyStrength = ((ElGamalPublicBCPGKey)key).getP().bitLength(); } + else if (key instanceof ECPublicBCPGKey) + { + this.keyStrength = ECNamedCurveTable.getByOID(((ECPublicBCPGKey)key).getCurveOID()).getCurve().getFieldSize(); + } } } - + /** * Create a PGP public key from a packet descriptor using the passed in fingerPrintCalculator to do calculate * the fingerprint and keyID. @@ -204,12 +210,23 @@ /** * @return number of valid days from creation time - zero means no * expiry. + * @deprecated use getValidSeconds(): greater than version 3 keys may be valid for less than a day. */ public int getValidDays() { if (publicPk.getVersion() > 3) { - return (int)(this.getValidSeconds() / (24 * 60 * 60)); + long delta = this.getValidSeconds() % (24 * 60 * 60); + int days = (int)(this.getValidSeconds() / (24 * 60 * 60)); + + if (delta > 0 && days == 0) + { + return 1; + } + else + { + return days; + } } else { @@ -340,7 +357,7 @@ int algorithm = publicPk.getAlgorithm(); return ((algorithm == RSA_GENERAL) || (algorithm == RSA_ENCRYPT) - || (algorithm == ELGAMAL_ENCRYPT) || (algorithm == ELGAMAL_GENERAL)); + || (algorithm == ELGAMAL_ENCRYPT) || (algorithm == ELGAMAL_GENERAL) || algorithm == ECDH); } /** @@ -365,7 +382,7 @@ /** * Return the strength of the key in bits. * - * @return bit strenght of key. + * @return bit strength of key. */ public int getBitStrength() { @@ -391,7 +408,28 @@ return temp.iterator(); } - + + /** + * Return any userIDs associated with the key in raw byte form. No attempt is made + * to convert the IDs into Strings. + * + * @return an iterator of Strings. + */ + public Iterator getRawUserIDs() + { + List temp = new ArrayList(); + + for (int i = 0; i != ids.size(); i++) + { + if (ids.get(i) instanceof UserIDPacket) + { + temp.add(((UserIDPacket)ids.get(i)).getRawID()); + } + } + + return temp.iterator(); + } + /** * Return any user attribute vectors associated with the key. * @@ -421,15 +459,19 @@ public Iterator getSignaturesForID( String id) { - for (int i = 0; i != ids.size(); i++) - { - if (id.equals(ids.get(i))) - { - return ((ArrayList)idSigs.get(i)).iterator(); - } - } - - return null; + return getSignaturesForID(new UserIDPacket(id)); + } + + /** + * Return any signatures associated with the passed in id. + * + * @param rawID the id to be matched in raw byte form. + * @return an iterator of PGPSignature objects. + */ + public Iterator getSignaturesForID( + byte[] rawID) + { + return getSignaturesForID(new UserIDPacket(rawID)); } /** @@ -455,7 +497,21 @@ return sigs.iterator(); } - + + private Iterator getSignaturesForID( + UserIDPacket id) + { + for (int i = 0; i != ids.size(); i++) + { + if (id.equals(ids.get(i))) + { + return ((ArrayList)idSigs.get(i)).iterator(); + } + } + + return null; + } + /** * Return an iterator of signatures associated with the passed in user attributes. * @@ -557,13 +613,45 @@ { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - this.encode(bOut); + this.encode(bOut, false); return bOut.toByteArray(); } - + + /** + * Return an encoding of the key, with trust packets stripped out if forTransfer is true. + * + * @param forTransfer if the purpose of encoding is to send key to other users. + * @return a encoded byte array representing the key. + * @throws IOException in case of encoding error. + */ + public byte[] getEncoded(boolean forTransfer) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + this.encode(bOut, forTransfer); + + return bOut.toByteArray(); + } + + public void encode( + OutputStream outStream) + throws IOException + { + encode(outStream, false); + } + + /** + * Encode the key to outStream, with trust packets stripped out if forTransfer is true. + * + * @param outStream stream to write the key encoding to. + * @param forTransfer if the purpose of encoding is to send key to other users. + * @throws IOException in case of encoding error. + */ public void encode( - OutputStream outStream) + OutputStream outStream, + boolean forTransfer) throws IOException { BCPGOutputStream out; @@ -578,7 +666,7 @@ } out.writePacket(publicPk); - if (trustPk != null) + if (!forTransfer && trustPk != null) { out.writePacket(trustPk); } @@ -605,7 +693,7 @@ out.writePacket(new UserAttributePacket(v.toSubpacketArray())); } - if (idTrusts.get(i) != null) + if (!forTransfer && idTrusts.get(i) != null) { out.writePacket((ContainedPacket)idTrusts.get(i)); } @@ -613,7 +701,7 @@ List sigs = (List)idSigs.get(i); for (int j = 0; j != sigs.size(); j++) { - ((PGPSignature)sigs.get(j)).encode(out); + ((PGPSignature)sigs.get(j)).encode(out, forTransfer); } } } @@ -621,18 +709,29 @@ { for (int j = 0; j != subSigs.size(); j++) { - ((PGPSignature)subSigs.get(j)).encode(out); + ((PGPSignature)subSigs.get(j)).encode(out, forTransfer); } } } - + /** * Check whether this (sub)key has a revocation signature on it. - * + * * @return boolean indicating whether this (sub)key has been revoked. + * @deprecated this method is poorly named, use hasRevocation(). */ public boolean isRevoked() { + return hasRevocation(); + } + + /** + * Check whether this (sub)key has a revocation signature on it. + * + * @return boolean indicating whether this (sub)key has had a (possibly invalid) revocation attached.. + */ + public boolean hasRevocation() + { int ns = 0; boolean revoked = false; @@ -660,6 +759,21 @@ return revoked; } + /** + * Add a certification for an id to the given public key. + * + * @param key the key the certification is to be added to. + * @param rawID the raw bytes making up the user id.. + * @param certification the new certification. + * @return the re-certified key. + */ + public static PGPPublicKey addCertification( + PGPPublicKey key, + byte[] rawID, + PGPSignature certification) + { + return addCert(key, new UserIDPacket(rawID), certification); + } /** * Add a certification for an id to the given public key. @@ -674,7 +788,7 @@ String id, PGPSignature certification) { - return addCert(key, id, certification); + return addCert(key, new UserIDPacket(id), certification); } /** @@ -752,7 +866,21 @@ PGPPublicKey key, String id) { - return removeCert(key, id); + return removeCert(key, new UserIDPacket(id)); + } + + /** + * Remove any certifications associated with a given id on a key. + * + * @param key the key the certifications are to be removed from. + * @param rawID the id that is to be removed in raw byte form. + * @return the re-certified key, null if the id was not found on the key. + */ + public static PGPPublicKey removeCertification( + PGPPublicKey key, + byte[] rawID) + { + return removeCert(key, new UserIDPacket(rawID)); } private static PGPPublicKey removeCert( @@ -783,6 +911,22 @@ /** * Remove a certification associated with a given id on a key. + * + * @param key the key the certifications are to be removed from. + * @param id the id that the certification is to be removed from (in its raw byte form) + * @param certification the certification to be removed. + * @return the re-certified key, null if the certification was not found. + */ + public static PGPPublicKey removeCertification( + PGPPublicKey key, + byte[] id, + PGPSignature certification) + { + return removeCert(key, new UserIDPacket(id), certification); + } + + /** + * Remove a certification associated with a given id on a key. * * @param key the key the certifications are to be removed from. * @param id the id that the certification is to be removed from. @@ -794,7 +938,7 @@ String id, PGPSignature certification) { - return removeCert(key, id, certification); + return removeCert(key, new UserIDPacket(id), certification); } /** @@ -902,15 +1046,15 @@ if (!found) { - for (Iterator it = key.getUserIDs(); it.hasNext();) + for (Iterator it = key.getRawUserIDs(); it.hasNext();) { - String id = (String)it.next(); + UserIDPacket id = (UserIDPacket)it.next(); for (Iterator sIt = key.getSignaturesForID(id); sIt.hasNext();) { if (certification == sIt.next()) { found = true; - returnKey = PGPPublicKey.removeCertification(returnKey, id, certification); + returnKey = PGPPublicKey.removeCertification(returnKey, id.getRawID(), certification); } } } diff -Nru bouncycastle-1.55/pg/src/main/j2me/org/bouncycastle/openpgp/PGPSignature.java bouncycastle-1.56/pg/src/main/j2me/org/bouncycastle/openpgp/PGPSignature.java --- bouncycastle-1.55/pg/src/main/j2me/org/bouncycastle/openpgp/PGPSignature.java 2014-03-21 02:20:43.000000000 +0000 +++ bouncycastle-1.56/pg/src/main/j2me/org/bouncycastle/openpgp/PGPSignature.java 2016-12-21 06:13:19.000000000 +0000 @@ -104,6 +104,16 @@ return sigPck.getHashAlgorithm(); } + /** + * Return true if this signature represents a certification. + * + * @return true if this signature represents a certification, false otherwise. + */ + public boolean isCertification() + { + return isCertification(getSignatureType()); + } + public void init(PGPContentVerifierBuilderProvider verifierBuilderProvider, PGPPublicKey pubKey) throws PGPException { @@ -117,7 +127,6 @@ public void update( byte b) - throws PGPSignatureException { if (signatureType == PGPSignature.CANONICAL_TEXT_DOCUMENT) { @@ -149,7 +158,6 @@ public void update( byte[] bytes) - throws PGPSignatureException { this.update(bytes, 0, bytes.length); } @@ -158,7 +166,6 @@ byte[] bytes, int off, int length) - throws PGPSignatureException { if (signatureType == PGPSignature.CANONICAL_TEXT_DOCUMENT) { @@ -176,7 +183,6 @@ } private void byteUpdate(byte b) - throws PGPSignatureException { try { @@ -184,12 +190,11 @@ } catch (IOException e) { - throw new PGPSignatureException(e.getMessage(), e); + throw new PGPRuntimeOperationException(e.getMessage(), e); } } private void blockUpdate(byte[] block, int off, int len) - throws PGPSignatureException { try { @@ -197,7 +202,7 @@ } catch (IOException e) { - throw new PGPSignatureException(e.getMessage(), e); + throw new PGPRuntimeOperationException(e.getMessage(), e); } } @@ -212,7 +217,7 @@ } catch (IOException e) { - throw new PGPSignatureException(e.getMessage(), e); + throw new PGPException(e.getMessage(), e); } return verifier.verify(this.getSignature()); @@ -220,7 +225,6 @@ private void updateWithIdData(int header, byte[] idBytes) - throws PGPException { this.update((byte)header); this.update((byte)(idBytes.length >> 24)); @@ -317,6 +321,37 @@ } /** + * Verify the signature as certifying the passed in public key as associated + * with the passed in rawID. + * + * @param rawID id the key was stored under in its raw byte form. + * @param key the key to be verified. + * @return true if the signature matches, false otherwise. + * @throws PGPException + */ + public boolean verifyCertification( + byte[] rawID, + PGPPublicKey key) + throws PGPException + { + if (verifier == null) + { + throw new PGPException("PGPSignature not initialised - call init()."); + } + + updateWithPublicKey(key); + + // + // hash in the rawID + // + updateWithIdData(0xb4, rawID); + + addTrailer(); + + return verifier.verify(this.getSignature()); + } + + /** * Verify a certification for the passed in key against the passed in * master key. * @@ -344,7 +379,6 @@ } private void addTrailer() - throws PGPSignatureException { try { @@ -354,7 +388,7 @@ } catch (IOException e) { - throw new PGPSignatureException(e.getMessage(), e); + throw new PGPRuntimeOperationException(e.getMessage(), e); } } @@ -375,7 +409,8 @@ } if (this.getSignatureType() != KEY_REVOCATION - && this.getSignatureType() != SUBKEY_REVOCATION) + && this.getSignatureType() != SUBKEY_REVOCATION + && this.getSignatureType() != DIRECT_KEY) { throw new PGPException("signature is not a key signature"); } @@ -491,9 +526,41 @@ return bOut.toByteArray(); } - + + /** + * Return an encoding of the signature, with trust packets stripped out if forTransfer is true. + * + * @param forTransfer if the purpose of encoding is to send key to other users. + * @return a encoded byte array representing the key. + * @throws IOException in case of encoding error. + */ + public byte[] getEncoded(boolean forTransfer) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + this.encode(bOut, forTransfer); + + return bOut.toByteArray(); + } + public void encode( - OutputStream outStream) + OutputStream outStream) + throws IOException + { + encode(outStream, false); + } + + /** + * Encode the signature to outStream, with trust packets stripped out if forTransfer is true. + * + * @param outStream stream to write the key encoding to. + * @param forTransfer if the purpose of encoding is to send key to other users. + * @throws IOException in case of encoding error. + */ + public void encode( + OutputStream outStream, + boolean forTransfer) throws IOException { BCPGOutputStream out; @@ -508,7 +575,7 @@ } out.writePacket(sigPck); - if (trustPck != null) + if (!forTransfer && trustPck != null) { out.writePacket(trustPck); } @@ -531,4 +598,18 @@ return keyBytes; } + + /** + * Return true if the passed in signature type represents a certification, false if the signature type is not. + * + * @param signatureType + * @return true if signatureType is a certification, false otherwise. + */ + public static boolean isCertification(int signatureType) + { + return PGPSignature.DEFAULT_CERTIFICATION == signatureType + || PGPSignature.NO_CERTIFICATION == signatureType + || PGPSignature.CASUAL_CERTIFICATION == signatureType + || PGPSignature.POSITIVE_CERTIFICATION == signatureType; + } } diff -Nru bouncycastle-1.55/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java bouncycastle-1.56/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java --- bouncycastle-1.55/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java 2014-06-21 04:21:33.000000000 +0000 +++ bouncycastle-1.56/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java 2016-11-04 04:04:40.000000000 +0000 @@ -19,7 +19,6 @@ import org.bouncycastle.crypto.digests.TigerDigest; import org.bouncycastle.crypto.encodings.PKCS1Encoding; import org.bouncycastle.crypto.engines.AESEngine; -import org.bouncycastle.crypto.engines.AESFastEngine; import org.bouncycastle.crypto.engines.BlowfishEngine; import org.bouncycastle.crypto.engines.CAST5Engine; import org.bouncycastle.crypto.engines.CamelliaEngine; @@ -134,7 +133,7 @@ case SymmetricKeyAlgorithmTags.AES_128: case SymmetricKeyAlgorithmTags.AES_192: case SymmetricKeyAlgorithmTags.AES_256: - return new RFC3394WrapEngine(new AESFastEngine()); + return new RFC3394WrapEngine(new AESEngine()); case SymmetricKeyAlgorithmTags.CAMELLIA_128: case SymmetricKeyAlgorithmTags.CAMELLIA_192: case SymmetricKeyAlgorithmTags.CAMELLIA_256: diff -Nru bouncycastle-1.55/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java bouncycastle-1.56/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java --- bouncycastle-1.55/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java 2016-01-29 06:20:43.000000000 +0000 +++ bouncycastle-1.56/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java 2016-12-16 21:16:03.000000000 +0000 @@ -613,13 +613,45 @@ { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - this.encode(bOut); + this.encode(bOut, false); return bOut.toByteArray(); } - + + /** + * Return an encoding of the key, with trust packets stripped out if forTransfer is true. + * + * @param forTransfer if the purpose of encoding is to send key to other users. + * @return a encoded byte array representing the key. + * @throws IOException in case of encoding error. + */ + public byte[] getEncoded(boolean forTransfer) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + this.encode(bOut, forTransfer); + + return bOut.toByteArray(); + } + + public void encode( + OutputStream outStream) + throws IOException + { + encode(outStream, false); + } + + /** + * Encode the key to outStream, with trust packets stripped out if forTransfer is true. + * + * @param outStream stream to write the key encoding to. + * @param forTransfer if the purpose of encoding is to send key to other users. + * @throws IOException in case of encoding error. + */ public void encode( - OutputStream outStream) + OutputStream outStream, + boolean forTransfer) throws IOException { BCPGOutputStream out; @@ -634,7 +666,7 @@ } out.writePacket(publicPk); - if (trustPk != null) + if (!forTransfer && trustPk != null) { out.writePacket(trustPk); } @@ -661,7 +693,7 @@ out.writePacket(new UserAttributePacket(v.toSubpacketArray())); } - if (idTrusts.get(i) != null) + if (!forTransfer && idTrusts.get(i) != null) { out.writePacket((ContainedPacket)idTrusts.get(i)); } @@ -669,7 +701,7 @@ List sigs = (List)idSigs.get(i); for (int j = 0; j != sigs.size(); j++) { - ((PGPSignature)sigs.get(j)).encode(out); + ((PGPSignature)sigs.get(j)).encode(out, forTransfer); } } } @@ -677,7 +709,7 @@ { for (int j = 0; j != subSigs.size(); j++) { - ((PGPSignature)subSigs.get(j)).encode(out); + ((PGPSignature)subSigs.get(j)).encode(out, forTransfer); } } } @@ -1014,7 +1046,7 @@ if (!found) { - for (Iterator it = key.getUserIDs(); it.hasNext();) + for (Iterator it = key.getRawUserIDs(); it.hasNext();) { UserIDPacket id = (UserIDPacket)it.next(); for (Iterator sIt = key.getSignaturesForID(id); sIt.hasNext();) diff -Nru bouncycastle-1.55/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyRing.java bouncycastle-1.56/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyRing.java --- bouncycastle-1.55/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyRing.java 2016-01-29 07:09:06.000000000 +0000 +++ bouncycastle-1.56/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyRing.java 2016-12-16 21:16:19.000000000 +0000 @@ -198,16 +198,48 @@ return bOut.toByteArray(); } - + + /** + * Return an encoding of the key ring, with trust packets stripped out if forTransfer is true. + * + * @param forTransfer if the purpose of encoding is to send key to other users. + * @return a encoded byte array representing the key. + * @throws IOException in case of encoding error. + */ + public byte[] getEncoded(boolean forTransfer) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + this.encode(bOut, forTransfer); + + return bOut.toByteArray(); + } + + public void encode( + OutputStream outStream) + throws IOException + { + encode(outStream, false); + } + + /** + * Encode the key ring to outStream, with trust packets stripped out if forTransfer is true. + * + * @param outStream stream to write the key encoding to. + * @param forTransfer if the purpose of encoding is to send key to other users. + * @throws IOException in case of encoding error. + */ public void encode( - OutputStream outStream) + OutputStream outStream, + boolean forTransfer) throws IOException { for (int i = 0; i != keys.size(); i++) { PGPPublicKey k = (PGPPublicKey)keys.get(i); - - k.encode(outStream); + + k.encode(outStream, forTransfer); } } diff -Nru bouncycastle-1.55/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java bouncycastle-1.56/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java --- bouncycastle-1.55/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java 2016-01-29 04:01:34.000000000 +0000 +++ bouncycastle-1.56/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java 2016-12-16 21:12:29.000000000 +0000 @@ -526,9 +526,41 @@ return bOut.toByteArray(); } - + + /** + * Return an encoding of the signature, with trust packets stripped out if forTransfer is true. + * + * @param forTransfer if the purpose of encoding is to send key to other users. + * @return a encoded byte array representing the key. + * @throws IOException in case of encoding error. + */ + public byte[] getEncoded(boolean forTransfer) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + this.encode(bOut, forTransfer); + + return bOut.toByteArray(); + } + + public void encode( + OutputStream outStream) + throws IOException + { + encode(outStream, false); + } + + /** + * Encode the signature to outStream, with trust packets stripped out if forTransfer is true. + * + * @param outStream stream to write the key encoding to. + * @param forTransfer if the purpose of encoding is to send key to other users. + * @throws IOException in case of encoding error. + */ public void encode( - OutputStream outStream) + OutputStream outStream, + boolean forTransfer) throws IOException { BCPGOutputStream out; @@ -543,7 +575,7 @@ } out.writePacket(sigPck); - if (trustPck != null) + if (!forTransfer && trustPck != null) { out.writePacket(trustPck); } diff -Nru bouncycastle-1.55/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java bouncycastle-1.56/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java --- bouncycastle-1.55/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java 2016-04-12 04:09:33.000000000 +0000 +++ bouncycastle-1.56/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java 2016-11-24 03:35:43.000000000 +0000 @@ -18,6 +18,7 @@ import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.DecoderException; /** * PGP utilities. @@ -343,7 +344,7 @@ * * @param in the stream to be checked and possibly wrapped. * @return a stream that will return PGP binary encoded data. - * @throws IOException if an error occurs reading the stream, or initalising the + * @throws IOException if an error occurs reading the stream, or initialising the * {@link ArmoredInputStream}. */ public static InputStream getDecoderStream( @@ -414,17 +415,24 @@ System.arraycopy(buf, 0, firstBlock, 0, firstBlock.length); - byte[] decoded = Base64.decode(firstBlock); + try + { + byte[] decoded = Base64.decode(firstBlock); - // - // it's a base64 PGP block. - // - if ((decoded[0] & 0x80) != 0) + // + // it's a base64 PGP block. + // + if ((decoded[0] & 0x80) != 0) + { + return new ArmoredInputStream(in, false); + } + + return new ArmoredInputStream(in); + } + catch (DecoderException e) { - return new ArmoredInputStream(in, false); + throw new IOException(e.getMessage()); } - - return new ArmoredInputStream(in); } } diff -Nru bouncycastle-1.55/pg/src/test/java/org/bouncycastle/openpgp/test/PGPArmoredTest.java bouncycastle-1.56/pg/src/test/java/org/bouncycastle/openpgp/test/PGPArmoredTest.java --- bouncycastle-1.55/pg/src/test/java/org/bouncycastle/openpgp/test/PGPArmoredTest.java 2014-05-03 05:29:14.000000000 +0000 +++ bouncycastle-1.56/pg/src/test/java/org/bouncycastle/openpgp/test/PGPArmoredTest.java 2016-11-28 03:49:00.000000000 +0000 @@ -2,9 +2,11 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import org.bouncycastle.bcpg.ArmoredInputStream; import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.bouncycastle.openpgp.PGPUtil; import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; @@ -87,7 +89,25 @@ return matches; } - private void blankLineTest() throws Exception + private void pgpUtilTest() + throws Exception + { + // check decoder exception isn't escaping. + ByteArrayInputStream bIn = new ByteArrayInputStream(Strings.toByteArray("abcde")); + + try + { + PGPUtil.getDecoderStream(bIn); + fail("no exception"); + } + catch (IOException e) + { + // expected: ignore. + } + } + + private void blankLineTest() + throws Exception { byte[] blankLineBytes = Strings.toByteArray(blankLineData); ByteArrayInputStream bIn = new ByteArrayInputStream(blankLineBytes); @@ -240,6 +260,7 @@ } blankLineTest(); + pgpUtilTest(); } public String getName() diff -Nru bouncycastle-1.55/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java bouncycastle-1.56/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java --- bouncycastle-1.55/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java 2016-01-29 07:05:13.000000000 +0000 +++ bouncycastle-1.56/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java 2016-12-16 21:22:25.000000000 +0000 @@ -1,6 +1,7 @@ package org.bouncycastle.openpgp.test; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -10,9 +11,12 @@ import javax.crypto.Cipher; +import org.bouncycastle.bcpg.BCPGInputStream; import org.bouncycastle.bcpg.HashAlgorithmTags; +import org.bouncycastle.bcpg.Packet; import org.bouncycastle.bcpg.SecretKeyPacket; import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.bouncycastle.bcpg.TrustPacket; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ElGamalParameterSpec; import org.bouncycastle.openpgp.PGPEncryptedData; @@ -1536,7 +1540,47 @@ fail("wrong number of secret keyrings"); } } - + + public void shouldStripPreserveTrustPackets() + throws Exception + { + JcaPGPPublicKeyRingCollection pubRings = new JcaPGPPublicKeyRingCollection(pub2); + + for (Iterator it = pubRings.getKeyRings(); it.hasNext();) + { + PGPPublicKeyRing pubRing = (PGPPublicKeyRing)it.next(); + + byte[] enc = pubRing.getEncoded(true); + + if (trustPackets(enc) != 0) + { + fail("trust packet found"); + } + } + + byte[] ring = pubRings.getEncoded(); + + isTrue("trust packets missing", trustPackets(ring) == 10); + } + + private int trustPackets(byte[] enc) + throws IOException + { + BCPGInputStream bIn = new BCPGInputStream(new ByteArrayInputStream(enc)); + + Packet packet; + int count = 0; + while ((packet = bIn.readPacket()) != null) + { + if (packet instanceof TrustPacket) + { + count++; + } + } + + return count; + } + public void test3() throws Exception { @@ -2797,6 +2841,7 @@ testUmlaut(); testBadUserID(); testNoExportPrivateKey(); + shouldStripPreserveTrustPackets(); } catch (PGPException e) { diff -Nru bouncycastle-1.55/pg/test.bak bouncycastle-1.56/pg/test.bak --- bouncycastle-1.55/pg/test.bak 2016-05-09 23:42:04.000000000 +0000 +++ bouncycastle-1.56/pg/test.bak 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -This is a test payload! diff -Nru bouncycastle-1.55/pg/test.txt.asc bouncycastle-1.56/pg/test.txt.asc --- bouncycastle-1.55/pg/test.txt.asc 2016-05-09 23:42:04.000000000 +0000 +++ bouncycastle-1.56/pg/test.txt.asc 2016-11-21 03:52:12.000000000 +0000 @@ -8,9 +8,9 @@ -----BEGIN PGP SIGNATURE----- Version: BCPG v@RELEASE_NAME@ -iKIEAQECAAwFAlcxIEwFHHRlc3QACgkQbvydCviC6qp6bgQAkdH/S3EiDaXByjkx -mfxUb/o2/OhjnOtM7vkpc0ZQ1m/HdFdB+NAmx5g5EZaNTrkxYFqEWVFldtmf8eSR -jY4pgkN1M3qqajn3125TOSjnHZvqxmIe+qNrh0QgIwgzK8wYQb4vBx4mp10gtnhs -T3+5Xd1ckZsnazuhLfrNpFoRkHs= -=uS1a +iKIEAQECAAwFAlgyb2wFHHRlc3QACgkQ5wQ6u+9WndPv7wP+O3+yHCkgTxG6KV0w +5OTxhtTms98/UVEfazZ7gYxl3qTiWBQ0n66PDxhBbWQc8xg3CFTEBUWflxvbRlyz +XTatwpLqcHvI4k9akUCSSGkzOF1ii7v2AOvy9k/qZJYI7hF6JJyYqZkrwtBS79rk +H6LRBfNrVtLig138zfn9PrL1a1Q= +=XuwE -----END PGP SIGNATURE----- Binary files /tmp/tmpowJLLf/jkZ0WCu6hH/bouncycastle-1.55/pg/test.txt.bpg and /tmp/tmpowJLLf/lAtENdT3zU/bouncycastle-1.56/pg/test.txt.bpg differ diff -Nru bouncycastle-1.55/pkix/build.gradle bouncycastle-1.56/pkix/build.gradle --- bouncycastle-1.55/pkix/build.gradle 2015-07-29 23:12:48.000000000 +0000 +++ bouncycastle-1.56/pkix/build.gradle 2016-11-13 00:33:03.000000000 +0000 @@ -3,6 +3,8 @@ compile project(':prov') } +jar.baseName = "bcpkix-jdk15on" + cobertura { coverageDirs = [ "${rootProject.projectDir}/core/build/classes/main", diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cert/dane/DANEEntryFactory.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cert/dane/DANEEntryFactory.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cert/dane/DANEEntryFactory.java 2015-01-21 05:50:54.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cert/dane/DANEEntryFactory.java 2016-11-09 09:35:16.000000000 +0000 @@ -22,6 +22,7 @@ /** * Return a DANEEntry for the passed in email address and certificate. + * This method sets the entry's certificate usage field to 3. * * @param emailAddress the emails address of interest. * @param certificate the certificate to be associated with the email address. @@ -30,10 +31,29 @@ public DANEEntry createEntry(String emailAddress, X509CertificateHolder certificate) throws DANEException { + return createEntry(emailAddress, DANEEntry.CERT_USAGE_ACCEPT, certificate); + } + + /** + * Return a DANEEntry for the passed in email address and certificate. + * + * @param emailAddress the emails address of interest. + * @param certUsage the certificate usage field value to use. + * @param certificate the certificate to be associated with the email address. + * @throws DANEException in case of issue generating a matching name. + */ + public DANEEntry createEntry(String emailAddress, int certUsage, X509CertificateHolder certificate) + throws DANEException + { + if (certUsage < 0 || certUsage > 3) + { + throw new DANEException("unknown certificate usage: " + certUsage); + } + DANEEntrySelector entrySelector = selectorFactory.createSelector(emailAddress); byte[] flags = new byte[3]; - flags[DANEEntry.CERT_USAGE] = 3; + flags[DANEEntry.CERT_USAGE] = (byte)certUsage; flags[DANEEntry.SELECTOR] = 0; flags[DANEEntry.MATCHING_TYPE] = 0; diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cert/dane/DANEEntry.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cert/dane/DANEEntry.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cert/dane/DANEEntry.java 2015-01-21 05:50:54.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cert/dane/DANEEntry.java 2016-11-08 02:32:29.000000000 +0000 @@ -10,6 +10,11 @@ */ public class DANEEntry { + public static final int CERT_USAGE_CA = 0; + public static final int CERT_USAGE_PKIX_VALIDATE = 1; + public static final int CERT_USAGE_TRUST_ANCHOR = 2; + public static final int CERT_USAGE_ACCEPT = 3; + static final int CERT_USAGE = 0; static final int SELECTOR = 1; static final int MATCHING_TYPE = 2; @@ -78,6 +83,6 @@ public static boolean isValidCertificate(byte[] data) { // TODO: perhaps validate ASN.1 data as well... - return (data[CERT_USAGE] == 3 && data[SELECTOR] == 0 && data[MATCHING_TYPE] == 0); + return ((data[CERT_USAGE] >= 0 || data[CERT_USAGE] <= 3)&& data[SELECTOR] == 0 && data[MATCHING_TYPE] == 0); } } diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java 2016-01-20 03:28:15.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java 2016-11-18 00:39:08.000000000 +0000 @@ -100,27 +100,13 @@ NamingEnumeration bindings; if (domainName.indexOf("_smimecert.") > 0) { - bindings = ctx.listBindings(domainName); - // need to use fully qualified domain name if using named DNS server. Attributes attrs = ctx.getAttributes(domainName, new String[]{DANE_TYPE}); Attribute smimeAttr = attrs.get(DANE_TYPE); if (smimeAttr != null) { - byte[] data = (byte[])attrs.get(DANE_TYPE).get(); - - if (DANEEntry.isValidCertificate(data)) - { - try - { - entries.add(new DANEEntry(domainName, data)); - } - catch (IOException e) - { - throw new DANEException("Exception parsing entry: " + e.getMessage(), e); - } - } + addEntries(entries, domainName, smimeAttr); } } else @@ -141,25 +127,14 @@ if (smimeAttr != null) { - byte[] data = (byte[])attrs.get(DANE_TYPE).get(); + String fullName = sc.getNameInNamespace(); + String domainName = fullName.substring(1, fullName.length() - 1); - if (DANEEntry.isValidCertificate(data)) - { - try - { - String fullName = sc.getNameInNamespace(); - - entries.add(new DANEEntry(fullName.substring(1, fullName.length() - 1), data)); - } - catch (IOException e) - { - throw new DANEException("Exception parsing entry: " + e.getMessage(), e); - } - } + addEntries(entries, domainName, smimeAttr); } } } - ; + return entries; } catch (NamingException e) @@ -169,4 +144,25 @@ } }; } + + private void addEntries(List entries, String domainName, Attribute smimeAttr) + throws NamingException, DANEException + { + for (int index = 0; index != smimeAttr.size(); index++) + { + byte[] data = (byte[])smimeAttr.get(index); + + if (DANEEntry.isValidCertificate(data)) + { + try + { + entries.add(new DANEEntry(domainName, data)); + } + catch (IOException e) + { + throw new DANEException("Exception parsing entry: " + e.getMessage(), e); + } + } + } + } } diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java 2013-03-13 04:09:06.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java 2016-09-09 00:47:33.000000000 +0000 @@ -17,7 +17,7 @@ public CMSAbsentContent() { - this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId())); + this(CMSObjectIdentifiers.data); } public CMSAbsentContent( diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java 2015-06-27 07:40:36.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java 2016-12-09 20:43:30.000000000 +0000 @@ -51,8 +51,8 @@ /** * Create a standard attribute table from the passed in parameters - this will - * normally include contentType, signingTime, and messageDigest. If the constructor - * using an AttributeTable was used, entries in it for contentType, signingTime, and + * normally include contentType, signingTime, messageDigest, and CMS algorithm protection. + * If the constructor using an AttributeTable was used, entries in it for contentType, signingTime, and * messageDigest will override the generated ones. * * @param parameters source parameters for table generation. diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java 2016-03-01 14:12:55.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java 2016-08-19 02:18:59.000000000 +0000 @@ -423,7 +423,7 @@ CMSUtils.loadParameters(params, sParams); - mac.init(sKey, params.getParameterSpec(IvParameterSpec.class)); + mac.init(sKey, params.getParameterSpec(AlgorithmParameterSpec.class)); } catch (NoSuchAlgorithmException e) { diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java 2015-07-06 04:17:11.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java 2016-08-19 01:15:15.000000000 +0000 @@ -22,6 +22,9 @@ import org.bouncycastle.operator.SecretKeySizeProvider; import org.bouncycastle.operator.jcajce.JceGenericKey; +/** + * Builder for the content encryptor in EnvelopedData - used to encrypt the actual transmitted content. + */ public class JceCMSContentEncryptorBuilder { private static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE; @@ -32,6 +35,7 @@ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); private SecureRandom random; + private AlgorithmParameters algorithmParameters; public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID) { @@ -70,6 +74,12 @@ } } + /** + * Set the provider to use for content encryption. + * + * @param provider the provider object to use for cipher and default parameters creation. + * @return the current builder instance. + */ public JceCMSContentEncryptorBuilder setProvider(Provider provider) { this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); @@ -77,6 +87,12 @@ return this; } + /** + * Set the provider to use for content encryption (by name) + * + * @param providerName the name of the provider to use for cipher and default parameters creation. + * @return the current builder instance. + */ public JceCMSContentEncryptorBuilder setProvider(String providerName) { this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); @@ -84,6 +100,12 @@ return this; } + /** + * Provide a specified source of randomness to be used for session key and IV/nonce generation. + * + * @param random the secure random to use. + * @return the current builder instance. + */ public JceCMSContentEncryptorBuilder setSecureRandom(SecureRandom random) { this.random = random; @@ -91,10 +113,23 @@ return this; } + /** + * Provide a set of algorithm parameters for the content encryption cipher to use. + * + * @param algorithmParameters algorithmParameters for content encryption. + * @return the current builder instance. + */ + public JceCMSContentEncryptorBuilder setAlgorithmParameters(AlgorithmParameters algorithmParameters) + { + this.algorithmParameters = algorithmParameters; + + return this; + } + public OutputEncryptor build() throws CMSException { - return new CMSOutputEncryptor(encryptionOID, keySize, random); + return new CMSOutputEncryptor(encryptionOID, keySize, algorithmParameters, random); } private class CMSOutputEncryptor @@ -104,7 +139,7 @@ private AlgorithmIdentifier algorithmIdentifier; private Cipher cipher; - CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random) + CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random) throws CMSException { KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID); @@ -125,7 +160,11 @@ cipher = helper.createCipher(encryptionOID); encKey = keyGen.generateKey(); - AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random); + + if (params == null) + { + params = helper.generateParameters(encryptionOID, encKey, random); + } try { diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java 2015-07-08 06:35:56.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java 2016-08-19 03:05:14.000000000 +0000 @@ -1,21 +1,15 @@ package org.bouncycastle.cms.jcajce; import java.io.OutputStream; -import java.security.AlgorithmParameterGenerator; import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; import java.security.Provider; import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.RC2ParameterSpec; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.cms.CMSException; import org.bouncycastle.jcajce.io.MacOutputStream; @@ -29,6 +23,7 @@ private final int keySize; private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + private AlgorithmParameters algorithmParameters; private SecureRandom random; public JceCMSMacCalculatorBuilder(ASN1ObjectIdentifier macOID) @@ -42,6 +37,12 @@ this.keySize = keySize; } + /** + * Set the provider to use for content encryption. + * + * @param provider the provider object to use for MAC and default parameters creation. + * @return the current builder instance. + */ public JceCMSMacCalculatorBuilder setProvider(Provider provider) { this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); @@ -49,6 +50,12 @@ return this; } + /** + * Set the provider to use for content encryption (by name) + * + * @param providerName the name of the provider to use for MAC and default parameters creation. + * @return the current builder instance. + */ public JceCMSMacCalculatorBuilder setProvider(String providerName) { this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); @@ -56,6 +63,12 @@ return this; } + /** + * Provide a specified source of randomness to be used for session key and IV/nonce generation. + * + * @param random the secure random to use. + * @return the current builder instance. + */ public JceCMSMacCalculatorBuilder setSecureRandom(SecureRandom random) { this.random = random; @@ -63,10 +76,23 @@ return this; } + /** + * Provide a set of algorithm parameters for the content MAC calculator to use. + * + * @param algorithmParameters algorithmParameters for MAC initialisation. + * @return the current builder instance. + */ + public JceCMSMacCalculatorBuilder setAlgorithmParameters(AlgorithmParameters algorithmParameters) + { + this.algorithmParameters = algorithmParameters; + + return this; + } + public MacCalculator build() throws CMSException { - return new CMSMacCalculator(macOID, keySize, random); + return new CMSMacCalculator(macOID, keySize, algorithmParameters, random); } private class CMSMacCalculator @@ -75,9 +101,8 @@ private SecretKey encKey; private AlgorithmIdentifier algorithmIdentifier; private Mac mac; - private SecureRandom random; - CMSMacCalculator(ASN1ObjectIdentifier macOID, int keySize, SecureRandom random) + CMSMacCalculator(ASN1ObjectIdentifier macOID, int keySize, AlgorithmParameters params, SecureRandom random) throws CMSException { KeyGenerator keyGen = helper.createKeyGenerator(macOID); @@ -87,8 +112,6 @@ random = new SecureRandom(); } - this.random = random; - if (keySize < 0) { keyGen.init(random); @@ -100,9 +123,12 @@ encKey = keyGen.generateKey(); - AlgorithmParameterSpec paramSpec = generateParameterSpec(macOID, encKey); + if (params == null) + { + params = helper.generateParameters(macOID, encKey, random); + } - algorithmIdentifier = helper.getAlgorithmIdentifier(macOID, paramSpec); + algorithmIdentifier = helper.getAlgorithmIdentifier(macOID, params); mac = helper.createContentMac(encKey, algorithmIdentifier); } @@ -125,31 +151,5 @@ { return new JceGenericKey(algorithmIdentifier, encKey); } - - protected AlgorithmParameterSpec generateParameterSpec(ASN1ObjectIdentifier macOID, SecretKey encKey) - throws CMSException - { - try - { - if (macOID.equals(PKCSObjectIdentifiers.RC2_CBC)) - { - byte[] iv = new byte[8]; - - random.nextBytes(iv); - - return new RC2ParameterSpec(encKey.getEncoded().length * 8, iv); - } - - AlgorithmParameterGenerator pGen = helper.createAlgorithmParameterGenerator(macOID); - - AlgorithmParameters p = pGen.generateParameters(); - - return p.getParameterSpec(IvParameterSpec.class); - } - catch (GeneralSecurityException e) - { - return null; - } - } } } diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java 2013-04-12 12:39:19.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java 2016-12-21 04:23:52.000000000 +0000 @@ -18,7 +18,7 @@ private org.bouncycastle.asn1.dvcs.DVCSResponse asn1; /** - * Constructs DVCRequest from CMS SignedData object. + * Constructs DVCResponse from CMS SignedData object. * * @param signedData the CMS SignedData object containing the request * @throws org.bouncycastle.dvcs.DVCSConstructionException @@ -30,7 +30,7 @@ } /** - * Construct a DVCS Request from a ContentInfo + * Construct a DVCS Response from a ContentInfo * * @param contentInfo the contentInfo representing the DVCSRequest * @throws org.bouncycastle.dvcs.DVCSConstructionException @@ -42,7 +42,7 @@ if (!DVCSObjectIdentifiers.id_ct_DVCSResponseData.equals(contentInfo.getContentType())) { - throw new DVCSConstructionException("ContentInfo not a DVCS Request"); + throw new DVCSConstructionException("ContentInfo not a DVCS Response"); } try diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/openssl/bc/PEMUtilities.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/openssl/bc/PEMUtilities.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/openssl/bc/PEMUtilities.java 2015-12-16 23:50:56.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/openssl/bc/PEMUtilities.java 2016-11-04 04:04:40.000000000 +0000 @@ -12,7 +12,7 @@ import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.PBEParametersGenerator; import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.engines.AESFastEngine; +import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.engines.BlowfishEngine; import org.bouncycastle.crypto.engines.DESEngine; import org.bouncycastle.crypto.engines.DESedeEngine; @@ -194,7 +194,7 @@ throw new EncryptionException("unknown AES encryption with private key: " + dekAlgName); } sKey = getKey(password, keyBits / 8, salt); - engine = new AESFastEngine(); + engine = new AESEngine(); } else { diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java 2015-01-16 02:46:54.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java 2016-09-14 06:59:22.000000000 +0000 @@ -110,6 +110,18 @@ algName = algorithm.getId(); } - return helper.createKeyFactory(algName); + try + { + return helper.createKeyFactory(algName); + } + catch (NoSuchAlgorithmException e) + { + if (algName.equals("ECDSA")) + { + return helper.createKeyFactory("EC"); // try a fall back + } + + throw e; + } } } diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java 2013-05-24 03:15:12.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java 2016-10-20 23:56:31.000000000 +0000 @@ -22,6 +22,7 @@ import org.bouncycastle.crypto.digests.SHA224Digest; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA3Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.operator.OperatorCreationException; @@ -69,6 +70,34 @@ return new SHA512Digest(); } }); + table.put(NISTObjectIdentifiers.id_sha3_224, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA3Digest(224); + } + }); + table.put(NISTObjectIdentifiers.id_sha3_256, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA3Digest(256); + } + }); + table.put(NISTObjectIdentifiers.id_sha3_384, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA3Digest(384); + } + }); + table.put(NISTObjectIdentifiers.id_sha3_512, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA3Digest(512); + } + }); table.put(PKCSObjectIdentifiers.md5, new BcDigestProvider() { public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/operator/DefaultAlgorithmNameFinder.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/operator/DefaultAlgorithmNameFinder.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/operator/DefaultAlgorithmNameFinder.java 2015-09-07 04:39:50.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/operator/DefaultAlgorithmNameFinder.java 2016-10-13 03:32:09.000000000 +0000 @@ -38,7 +38,7 @@ algorithms.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410-94"); algorithms.put(CryptoProObjectIdentifiers.gostR3411, "GOST3411"); algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1WITHCVC-ECDSA"); - algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224WITHPCVC-ECDSA"); + algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224WITHCVC-ECDSA"); algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256WITHCVC-ECDSA"); algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384WITHCVC-ECDSA"); algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512WITHCVC-ECDSA"); diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java 2015-10-01 07:21:05.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java 2016-11-22 20:45:26.000000000 +0000 @@ -5,6 +5,8 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.bc.BCObjectIdentifiers; +import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; @@ -45,11 +47,30 @@ digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, NISTObjectIdentifiers.id_sha512); digestOids.put(X9ObjectIdentifiers.id_dsa_with_sha1, OIWObjectIdentifiers.idSHA1); + digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA1, OIWObjectIdentifiers.idSHA1); + digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA224, NISTObjectIdentifiers.id_sha224); + digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA256, NISTObjectIdentifiers.id_sha256); + digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA384, NISTObjectIdentifiers.id_sha384); + digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(NISTObjectIdentifiers.dsa_with_sha224, NISTObjectIdentifiers.id_sha224); digestOids.put(NISTObjectIdentifiers.dsa_with_sha256, NISTObjectIdentifiers.id_sha256); digestOids.put(NISTObjectIdentifiers.dsa_with_sha384, NISTObjectIdentifiers.id_sha384); digestOids.put(NISTObjectIdentifiers.dsa_with_sha512, NISTObjectIdentifiers.id_sha512); + digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_224, NISTObjectIdentifiers.id_sha3_224); + digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_256, NISTObjectIdentifiers.id_sha3_256); + digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_384, NISTObjectIdentifiers.id_sha3_384); + digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_512, NISTObjectIdentifiers.id_sha3_512); + digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_224, NISTObjectIdentifiers.id_sha3_224); + digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_256, NISTObjectIdentifiers.id_sha3_256); + digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_384, NISTObjectIdentifiers.id_sha3_384); + digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_512, NISTObjectIdentifiers.id_sha3_512); + digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_224, NISTObjectIdentifiers.id_sha3_224); + digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_256, NISTObjectIdentifiers.id_sha3_256); + digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_384, NISTObjectIdentifiers.id_sha3_384); + digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_512, NISTObjectIdentifiers.id_sha3_512); + digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, TeleTrusTObjectIdentifiers.ripemd128); digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, TeleTrusTObjectIdentifiers.ripemd160); digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, TeleTrusTObjectIdentifiers.ripemd256); @@ -57,6 +78,9 @@ digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, CryptoProObjectIdentifiers.gostR3411); digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, CryptoProObjectIdentifiers.gostR3411); + digestOids.put(BCObjectIdentifiers.sphincs256_with_SHA3_512, NISTObjectIdentifiers.id_sha3_512); + digestOids.put(BCObjectIdentifiers.sphincs256_with_SHA512, NISTObjectIdentifiers.id_sha512); + digestNameToOids.put("SHA-1", OIWObjectIdentifiers.idSHA1); digestNameToOids.put("SHA-224", NISTObjectIdentifiers.id_sha224); digestNameToOids.put("SHA-256", NISTObjectIdentifiers.id_sha256); diff -Nru bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java --- bouncycastle-1.55/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java 2016-01-08 06:08:31.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java 2016-10-20 23:43:07.000000000 +0000 @@ -377,7 +377,7 @@ String name = MessageDigestUtils.getDigestName(oid); int dIndex = name.indexOf('-'); - if (dIndex > 0) + if (dIndex > 0 && !name.startsWith("SHA3")) { return name.substring(0, dIndex) + name.substring(dIndex + 1); } @@ -388,7 +388,6 @@ public X509Certificate convertCertificate(X509CertificateHolder certHolder) throws CertificateException { - try { CertificateFactory certFact = helper.createCertificateFactory("X.509"); diff -Nru bouncycastle-1.55/pkix/src/main/jdk1.1/org/bouncycastle/cert/dane/DANEEntry.java bouncycastle-1.56/pkix/src/main/jdk1.1/org/bouncycastle/cert/dane/DANEEntry.java --- bouncycastle-1.55/pkix/src/main/jdk1.1/org/bouncycastle/cert/dane/DANEEntry.java 2015-02-28 06:28:43.000000000 +0000 +++ bouncycastle-1.56/pkix/src/main/jdk1.1/org/bouncycastle/cert/dane/DANEEntry.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -package org.bouncycastle.cert.dane; - -import java.io.IOException; - -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.util.Arrays; - -/** - * Carrier class for a DANE entry. - */ -public class DANEEntry -{ - static final int CERT_USAGE = 0; - static final int SELECTOR = 1; - static final int MATCHING_TYPE = 2; - - private String domainName; - private byte[] flags; - private X509CertificateHolder certHolder; - - DANEEntry(String domainName, byte[] flags, X509CertificateHolder certHolder) - { - this.flags = flags; - this.domainName = domainName; - this.certHolder = certHolder; - } - - public DANEEntry(String domainName, byte[] data) - throws IOException - { - this(domainName, Arrays.copyOfRange(data, 0, 3), new X509CertificateHolder(Arrays.copyOfRange(data, 3, data.length))); - } - - public byte[] getFlags() - { - return Arrays.clone(flags); - } - - /** - * Return the certificate associated with this entry. - * - * @return the entry's certificate. - */ - public X509CertificateHolder getCertificate() - { - return certHolder; - } - - public String getDomainName() - { - return domainName; - } - - /** - * Return the full data string as it would appear in the DNS record - flags + encoding - * - * @return byte array representing the full data string. - * @throws IOException if there is an issue encoding the certificate inside this entry. - */ - public byte[] getRDATA() - throws IOException - { - byte[] certEnc = certHolder.getEncoded(); - byte[] data = new byte[flags.length + certEnc.length]; - - System.arraycopy(flags, 0, data, 0, flags.length); - System.arraycopy(certEnc, 0, data, flags.length, certEnc.length); - - return data; - } - - /** - * Return true if the byte string has the correct flag bytes to indicate a certificate entry. - * - * @param data the byte string of interest. - * @return true if flags indicate a valid certificate, false otherwise. - */ - public static boolean isValidCertificate(byte[] data) - { - // TODO: perhaps validate ASN.1 data as well... - return (data[CERT_USAGE] == 3 && data[SELECTOR] == 0 && data[MATCHING_TYPE] == 0); - } -} diff -Nru bouncycastle-1.55/pkix/src/test/java/org/bouncycastle/cert/crmf/test/AllTests.java bouncycastle-1.56/pkix/src/test/java/org/bouncycastle/cert/crmf/test/AllTests.java --- bouncycastle-1.55/pkix/src/test/java/org/bouncycastle/cert/crmf/test/AllTests.java 2016-01-08 06:39:32.000000000 +0000 +++ bouncycastle-1.56/pkix/src/test/java/org/bouncycastle/cert/crmf/test/AllTests.java 2016-09-08 20:19:33.000000000 +0000 @@ -9,6 +9,7 @@ import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; +import java.security.Signature; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPublicKey; import java.security.spec.MGF1ParameterSpec; @@ -22,12 +23,14 @@ import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.crmf.CRMFObjectIdentifiers; import org.bouncycastle.asn1.crmf.EncKeyWithID; import org.bouncycastle.asn1.crmf.EncryptedValue; +import org.bouncycastle.asn1.crmf.POPOSigningKey; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; @@ -110,6 +113,40 @@ } + public void testBasicMessage() + throws Exception + { + KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC); + + kGen.initialize(512); + + KeyPair kp = kGen.generateKeyPair(); + + JcaCertificateRequestMessageBuilder certReqBuild = new JcaCertificateRequestMessageBuilder(BigInteger.ONE); + + certReqBuild.setSubject(new X500Principal("CN=Test")) + .setPublicKey(kp.getPublic()) + .setProofOfPossessionSigningKeySigner(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(kp.getPrivate())); + + JcaCertificateRequestMessage certReqMsg = new JcaCertificateRequestMessage(certReqBuild.build()).setProvider(BC); + + + POPOSigningKey popoSign = POPOSigningKey.getInstance(certReqMsg.toASN1Structure().getPopo().getObject()); + + Signature sig = Signature.getInstance("SHA1withRSA", "BC"); + + sig.initVerify(certReqMsg.getPublicKey()); + + // this is the original approach in RFC 2511 - there's a typo in RFC 4211, the standard contradicts itself + // between 4.1. 3 and then a couple of paragraphs later. + sig.update(certReqMsg.toASN1Structure().getCertReq().getEncoded(ASN1Encoding.DER)); + + TestCase.assertTrue(sig.verify(popoSign.getSignature().getOctets())); + + TestCase.assertEquals(new X500Principal("CN=Test"), certReqMsg.getSubjectX500Principal()); + TestCase.assertEquals(kp.getPublic(), certReqMsg.getPublicKey()); + } + public void testBasicMessageWithArchiveControl() throws Exception { diff -Nru bouncycastle-1.55/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java bouncycastle-1.56/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java --- bouncycastle-1.55/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java 2016-02-10 00:41:58.000000000 +0000 +++ bouncycastle-1.56/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java 2016-10-20 23:40:21.000000000 +0000 @@ -1159,6 +1159,31 @@ "D2a8yuoaYDAIBgYqhQMCAgMDQQA8L8kJRLcnqeyn1en7U23Sw6pkfEQu3u0xFkVP" + "vFQ/3cHeF26NG+xxtZPz3TaTVXdoiYkXYiD02rEx1bUcM97i"); + private final byte[] sha3Cert = Base64.decode( + "MIID8jCCAqagAwIBAgIICfBykpzUT+IwQQYJKoZIhvcNAQEKMDSgDzANBglg" + + "hkgBZQMEAggFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAggFAKIDAgEg" + + "MCwxCzAJBgNVBAYTAkRFMQ4wDAYDVQQKDAV4aXBraTENMAsGA1UEAwwEUkNB" + + "MTAeFw0xNjEwMTgxODQzMjhaFw0yNjEwMTgxODQzMjdaMCwxCzAJBgNVBAYT" + + "AkRFMQ4wDAYDVQQKDAV4aXBraTENMAsGA1UEAwwEUkNBMTCCASIwDQYJKoZI" + + "hvcNAQEBBQADggEPADCCAQoCggEBAK/pzm1RASDYDg3WBXyW3AnAESRF/+li" + + "qh0X8Y89m+JFJeOi1u89bOSPjsFfo5SbRSElyRXedh/d37KrONg39NEKIcC6" + + "iSuiNfXu0D6nlSzhrQzmvHIyfLnm8N2JtHDr/hZIprOcFO+lZTJIjjrOVe9y" + + "lFGgGDd/uQCEJk1Cmi5Ivi9odeiN3z8lVlGNeN9/Q5n47ijuYWr73z/FyyAK" + + "gAG3B5nhAYWs4ft0O3JWBc0QJZzShqsRjm3SNhAqMDnRoTq04PFgbDYizV8T" + + "ydz2kCne79TDwsY4MckYYaGoNcPoQXVS+9YjQjI72ktSlxiJxodL9WMFl+ED" + + "5ZLBRIRsDJECAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MGoGCCsGAQUF" + + "BwEBBF4wXDAnBggrBgEFBQcwAoYbaHR0cDovL2V4YW1wbGUub3JnL1JDQTEu" + + "ZGVyMDEGCCsGAQUFBzABhiVodHRwOi8vbG9jYWxob3N0OjgwODAvb2NzcC9y" + + "ZXNwb25kZXIxMB0GA1UdDgQWBBRTXKdJI3P1kveLlRxPvzUfDnC8JjAOBgNV" + + "HQ8BAf8EBAMCAQYwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAggFAKEc" + + "MBoGCSqGSIb3DQEBCDANBglghkgBZQMEAggFAKIDAgEgA4IBAQCpSVaqOMKz" + + "6NT0+mivEhig9cKsglFhnWStKUtdhrG4HqOf6Qjny9Xvq1nE7x8e2xAoaZLd" + + "GMsNAWFCbwzoJrDL7Ct6itQ5ymxi2haN+Urc5UWJd/8C0R74OdP1uPCiljZ9" + + "DdjbNk/hS36UPYi+FT5r6Jr/1X/EqgL1MOUsSTEXdYlZH662zjbV4D9QSBzx" + + "ul9bYyWrqSZFKvKef4UQwUy8yXtChwiwp50mfJQBdVcIqPBYCgmLYclamjQx" + + "hlkk5VbZb4D/Cv4HxrdxpJfy/ewUZR7uHlzDx0/m4qjzNzWgq+sh3ZbveDrV" + + "wd/FDMFOxSIno9qgHtdfgXRwZJ+l07fF"); + private PublicKey dudPublicKey = new PublicKey() { public String getAlgorithm() @@ -1286,7 +1311,9 @@ PublicKey k = cert.getPublicKey(); - cert.verify(k); + X509CertificateHolder certHldr = new X509CertificateHolder(bytes); + + certHldr.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("BC").build(k)); // System.out.println(cert); } catch (Exception e) @@ -3045,7 +3072,8 @@ checkSelfSignedCertificate(15, gost34102001base); checkSelfSignedCertificate(16, gost341094A); checkSelfSignedCertificate(17, gost341094B); - checkSelfSignedCertificate(17, gost34102001A); + checkSelfSignedCertificate(18, gost34102001A); + checkSelfSignedCertificate(19, sha3Cert); checkCRL(1, crl1); diff -Nru bouncycastle-1.55/pkix/src/test/java/org/bouncycastle/cms/test/NewAuthenticatedDataTest.java bouncycastle-1.56/pkix/src/test/java/org/bouncycastle/cms/test/NewAuthenticatedDataTest.java --- bouncycastle-1.55/pkix/src/test/java/org/bouncycastle/cms/test/NewAuthenticatedDataTest.java 2015-06-28 02:43:35.000000000 +0000 +++ bouncycastle-1.56/pkix/src/test/java/org/bouncycastle/cms/test/NewAuthenticatedDataTest.java 2016-08-23 04:44:42.000000000 +0000 @@ -1,5 +1,7 @@ package org.bouncycastle.cms.test; +import java.io.IOException; +import java.security.AlgorithmParameters; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; @@ -16,13 +18,18 @@ import junit.framework.TestCase; import junit.framework.TestSuite; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.cms.AuthenticatedData; +import org.bouncycastle.asn1.cms.CCMParameters; import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; import org.bouncycastle.asn1.cms.ContentInfo; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.bouncycastle.asn1.util.ASN1Dump; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cms.CMSAlgorithm; @@ -147,6 +154,9 @@ throws Exception { tryKekAlgorithm(CMSTestUtil.makeDesede192Key(), new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6")); + + DEROctetString iv = new DEROctetString(Hex.decode("0001020304050607")); + tryKekAlgorithm(CMSTestUtil.makeDesede192Key(), new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"), iv.getEncoded()); } public void testKEKDESedeWithDigest() @@ -281,6 +291,53 @@ } } + public void testAES256CCM() + throws Exception + { + byte[] data = "Eric H. Echidna".getBytes(); + ASN1ObjectIdentifier macAlg = CMSAlgorithm.AES256_CCM; + AlgorithmParameters algParams = AlgorithmParameters.getInstance("CCM", BC); + + algParams.init(new CCMParameters(Hex.decode("000102030405060708090a0b"), 16).getEncoded()); + + CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator(); + + X509CertificateHolder origCert = new X509CertificateHolder(_origCert.getEncoded()); + + adGen.setOriginatorInfo(new OriginatorInfoGenerator(origCert).generate()); + + adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC)); + + CMSAuthenticatedData ad = adGen.generate( + new CMSProcessableByteArray(data), + new JceCMSMacCalculatorBuilder(macAlg).setAlgorithmParameters(algParams).setProvider(BC).build()); + + assertTrue(ad.getOriginatorInfo().getCertificates().getMatches(null).contains(origCert)); + + RecipientInformationStore recipients = ad.getRecipientInfos(); + + assertEquals(ad.getMacAlgOID(), macAlg.getId()); + + Collection c = recipients.getRecipients(); + + assertEquals(1, c.size()); + + Iterator it = c.iterator(); + + while (it.hasNext()) + { + RecipientInformation recipient = (RecipientInformation)it.next(); + + assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId()); + + byte[] recData = recipient.getContent(new JceKeyTransAuthenticatedRecipient(_reciKP.getPrivate()).setProvider(BC)); + + assertTrue(Arrays.equals(data, recData)); + assertEquals(16, ad.getMac().length); + assertTrue(Arrays.equals(ad.getMac(), recipient.getMac())); + } + } + public void testCMSAlgorithmProtection() throws Exception { @@ -465,6 +522,50 @@ if (it.hasNext()) { + RecipientInformation recipient = (RecipientInformation)it.next(); + + assertEquals(recipient.getKeyEncryptionAlgOID(), algOid.getId()); + + byte[] recData = recipient.getContent(new JceKEKAuthenticatedRecipient(kek).setProvider(BC)); + + assertTrue(Arrays.equals(data, recData)); + assertTrue(Arrays.equals(ad.getMac(), recipient.getMac())); + } + else + { + fail("no recipient found"); + } + } + + private void tryKekAlgorithm(SecretKey kek, ASN1ObjectIdentifier algOid, byte[] encodedParameters) + throws NoSuchAlgorithmException, NoSuchProviderException, CMSException, OperatorCreationException, IOException + { + byte[] data = "Eric H. Echidna".getBytes(); + + CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator(); + + byte[] kekId = new byte[]{1, 2, 3, 4, 5}; + + adGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC)); + + AlgorithmParameters algParams = AlgorithmParameters.getInstance(CMSAlgorithm.DES_EDE3_CBC.getId(), "BC"); + + algParams.init(encodedParameters); + + CMSAuthenticatedData ad = adGen.generate( + new CMSProcessableByteArray(data), + new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setAlgorithmParameters(algParams).setProvider(BC).build()); + + RecipientInformationStore recipients = ad.getRecipientInfos(); + + Collection c = recipients.getRecipients(); + Iterator it = c.iterator(); + + assertEquals(ad.getMacAlgOID(), CMSAuthenticatedDataGenerator.DES_EDE3_CBC); + assertEquals(ad.getMacAlgorithm().getParameters(), ASN1Primitive.fromByteArray(encodedParameters)); + + if (it.hasNext()) + { RecipientInformation recipient = (RecipientInformation)it.next(); assertEquals(recipient.getKeyEncryptionAlgOID(), algOid.getId()); diff -Nru bouncycastle-1.55/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java bouncycastle-1.56/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java --- bouncycastle-1.55/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java 2016-07-04 01:20:04.000000000 +0000 +++ bouncycastle-1.56/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java 2016-08-19 03:00:59.000000000 +0000 @@ -2,6 +2,7 @@ import java.io.IOException; import java.io.InputStreamReader; +import java.security.AlgorithmParameters; import java.security.GeneralSecurityException; import java.security.Key; import java.security.KeyFactory; @@ -39,9 +40,11 @@ import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.cms.Attribute; import org.bouncycastle.asn1.cms.AttributeTable; +import org.bouncycastle.asn1.cms.CCMParameters; import org.bouncycastle.asn1.cms.ContentInfo; import org.bouncycastle.asn1.cms.EncryptedContentInfo; import org.bouncycastle.asn1.cms.EnvelopedData; +import org.bouncycastle.asn1.cms.GCMParameters; import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; @@ -1145,9 +1148,14 @@ tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES192_GCM, NISTObjectIdentifiers.id_aes192_GCM); tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES256_GCM, NISTObjectIdentifiers.id_aes256_GCM); + byte[] nonce = Hex.decode("0102030405060708090a0b0c"); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES128_GCM, NISTObjectIdentifiers.id_aes128_GCM, new GCMParameters(nonce, 11).getEncoded()); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES128_CCM, NISTObjectIdentifiers.id_aes128_CCM); tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES192_CCM, NISTObjectIdentifiers.id_aes192_CCM); tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES256_CCM, NISTObjectIdentifiers.id_aes256_CCM); + + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES128_CCM, NISTObjectIdentifiers.id_aes128_CCM, new CCMParameters(nonce, 13).getEncoded()); } public void testAES192KEK() @@ -1259,9 +1267,60 @@ fail("no recipient found"); } - byte[] edData = ed.getEncoded(); + checkAlteredMAC(kek, algOid, ed.getEncoded()); + } + + private void tryKekAlgorithmAEAD(SecretKey kek, ASN1ObjectIdentifier algOid, ASN1ObjectIdentifier aeadAlgorithm, ASN1ObjectIdentifier baseOID, byte[] encodedParameters) + throws NoSuchAlgorithmException, NoSuchProviderException, CMSException, IOException + { + byte[] data = "WallaWallaWashington".getBytes(); + CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator(); + + byte[] kekId = new byte[]{1, 2, 3, 4, 5}; + + edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC)); + + AlgorithmParameters algParams = AlgorithmParameters.getInstance(aeadAlgorithm.getId(), BC); + + algParams.init(encodedParameters); + + CMSEnvelopedData ed = edGen.generate( + new CMSProcessableByteArray(data), + new JceCMSContentEncryptorBuilder(aeadAlgorithm).setProvider(BC).setAlgorithmParameters(algParams).build()); + + RecipientInformationStore recipients = ed.getRecipientInfos(); + + Collection c = recipients.getRecipients(); + Iterator it = c.iterator(); + + assertEquals(ed.getContentEncryptionAlgorithm().getAlgorithm(), baseOID); + assertEquals(ed.getContentEncryptionAlgorithm().getParameters(), ASN1Sequence.getInstance(encodedParameters)); + + if (it.hasNext()) + { + RecipientInformation recipient = (RecipientInformation)it.next(); + + assertEquals(algOid.getId(), recipient.getKeyEncryptionAlgOID()); + + byte[] recData = recipient.getContent(new JceKEKEnvelopedRecipient(kek).setKeySizeValidation(true).setProvider(BC)); + + assertTrue(Arrays.equals(data, recData)); + } + else + { + fail("no recipient found"); + } + + checkAlteredMAC(kek, algOid, ed.getEncoded()); + } - ContentInfo eContentInfo = ContentInfo.getInstance(edData); + private void checkAlteredMAC(SecretKey kek, ASN1ObjectIdentifier algOid, byte[] edData) + throws CMSException, IOException + { + CMSEnvelopedData ed; + RecipientInformationStore recipients; + Collection c; + Iterator it;ContentInfo eContentInfo = ContentInfo.getInstance(edData); EnvelopedData envD = EnvelopedData.getInstance(eContentInfo.getContent()); diff -Nru bouncycastle-1.55/pkix/src/test/java/org/bouncycastle/tsp/test/ParseTest.java bouncycastle-1.56/pkix/src/test/java/org/bouncycastle/tsp/test/ParseTest.java --- bouncycastle-1.55/pkix/src/test/java/org/bouncycastle/tsp/test/ParseTest.java 2014-03-02 20:50:40.000000000 +0000 +++ bouncycastle-1.56/pkix/src/test/java/org/bouncycastle/tsp/test/ParseTest.java 2016-10-15 01:42:21.000000000 +0000 @@ -370,7 +370,7 @@ throws Exception { requestParse(sha1Request, TSPAlgorithms.SHA1); - + requestParse(sha1noNonse, TSPAlgorithms.SHA1); requestParse(md5Request, TSPAlgorithms.MD5); @@ -385,7 +385,8 @@ unacceptableResponseParse(unacceptablePolicy); - generalizedTimeParse(generalizedTime); + // TODO: believe it or not but this contains invalid integers + //generalizedTimeParse(generalizedTime); v2SigningResponseParse(v2SigningCertResponse); } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java 2015-07-24 07:22:34.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java 2016-12-11 03:46:47.000000000 +0000 @@ -29,6 +29,11 @@ */ public PKCS12Key(char[] password, boolean useWrongZeroLengthConversion) { + if (password == null) + { + password = new char[0]; + } + this.password = new char[password.length]; this.useWrongZeroLengthConversion = useWrongZeroLengthConversion; diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java 2015-06-10 10:56:56.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java 2016-10-31 22:51:24.000000000 +0000 @@ -16,10 +16,12 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x9.DHDomainParameters; import org.bouncycastle.asn1.x9.DomainParameters; +import org.bouncycastle.asn1.x9.ValidationParams; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.crypto.params.DHPublicKeyParameters; +import org.bouncycastle.crypto.params.DHValidationParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; public class BCDHPublicKey @@ -29,6 +31,7 @@ private BigInteger y; + private transient DHPublicKeyParameters dhPublicKey; private transient DHParameterSpec dhSpec; private transient SubjectPublicKeyInfo info; @@ -37,6 +40,7 @@ { this.y = spec.getY(); this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG()); + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(spec.getP(), spec.getG())); } BCDHPublicKey( @@ -44,6 +48,7 @@ { this.y = key.getY(); this.dhSpec = key.getParams(); + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG())); } BCDHPublicKey( @@ -51,6 +56,7 @@ { this.y = params.getY(); this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL()); + this.dhPublicKey = params; } BCDHPublicKey( @@ -59,6 +65,7 @@ { this.y = y; this.dhSpec = dhSpec; + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG())); } public BCDHPublicKey( @@ -94,12 +101,23 @@ { this.dhSpec = new DHParameterSpec(params.getP(), params.getG()); } + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG())); } else if (id.equals(X9ObjectIdentifiers.dhpublicnumber)) { DomainParameters params = DomainParameters.getInstance(seq); this.dhSpec = new DHParameterSpec(params.getP(), params.getG()); + ValidationParams validationParams = params.getValidationParams(); + if (validationParams != null) + { + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), + new DHValidationParameters(validationParams.getSeed(), validationParams.getPgenCounter().intValue()))); + } + else + { + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), null)); + } } else { @@ -137,6 +155,11 @@ return y; } + public DHPublicKeyParameters engineGetKeyParameters() + { + return dhPublicKey; + } + private boolean isPKCSParam(ASN1Sequence seq) { if (seq.size() == 2) diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java 2015-12-05 20:26:38.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java 2016-12-22 02:37:12.000000000 +0000 @@ -21,30 +21,31 @@ import javax.crypto.interfaces.DHPrivateKey; import javax.crypto.interfaces.DHPublicKey; -import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.KeyEncoder; import org.bouncycastle.crypto.agreement.DHBasicAgreement; -import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.engines.DESedeEngine; import org.bouncycastle.crypto.engines.IESEngine; -import org.bouncycastle.crypto.engines.OldIESEngine; import org.bouncycastle.crypto.generators.DHKeyPairGenerator; import org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator; import org.bouncycastle.crypto.generators.KDF2BytesGenerator; import org.bouncycastle.crypto.macs.HMac; +import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.DHKeyGenerationParameters; import org.bouncycastle.crypto.params.DHKeyParameters; import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.crypto.params.DHPublicKeyParameters; -import org.bouncycastle.crypto.params.IESParameters; import org.bouncycastle.crypto.params.IESWithCipherParameters; +import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.crypto.parsers.DHIESPublicKeyParser; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.jcajce.provider.asymmetric.util.DHUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.IESUtil; +import org.bouncycastle.jcajce.provider.util.BadBlockException; import org.bouncycastle.jcajce.util.BCJcaJceHelper; import org.bouncycastle.jcajce.util.JcaJceHelper; import org.bouncycastle.jce.interfaces.IESKey; @@ -57,6 +58,7 @@ extends CipherSpi { private final JcaJceHelper helper = new BCJcaJceHelper(); + private final int ivLength; private IESEngine engine; private int state = -1; @@ -71,11 +73,13 @@ public IESCipher(IESEngine engine) { this.engine = engine; + this.ivLength = 0; } - public IESCipher(OldIESEngine engine) + public IESCipher(IESEngine engine, int ivLength) { this.engine = engine; + this.ivLength = ivLength; } public int engineGetBlockSize() @@ -106,6 +110,10 @@ public byte[] engineGetIV() { + if (engineSpec != null) + { + return engineSpec.getNonce(); + } return null; } @@ -257,7 +265,13 @@ // Use default parameters (including cipher key size) if none are specified if (engineSpec == null) { - this.engineSpec = IESUtil.guessParameterSpec(engine.getCipher()); + byte[] nonce = null; + if (ivLength != 0 && opmode == Cipher.ENCRYPT_MODE) + { + nonce = new byte[ivLength]; + random.nextBytes(nonce); + } + this.engineSpec = IESUtil.guessParameterSpec(engine.getCipher(), nonce); } else if (engineSpec instanceof IESParameterSpec) { @@ -268,6 +282,13 @@ throw new InvalidAlgorithmParameterException("must be passed IES parameters"); } + byte[] nonce = this.engineSpec.getNonce(); + + if (ivLength != 0 && (nonce == null || nonce.length != ivLength)) + { + throw new InvalidAlgorithmParameterException("NONCE in IES Parameters needs to be " + ivLength + " bytes long"); + } + // Parse the recipient's key if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) { @@ -329,7 +350,7 @@ } catch (InvalidAlgorithmParameterException e) { - throw new IllegalArgumentException("can't handle supplied parameter spec"); + throw new IllegalArgumentException("cannot handle supplied parameter spec: " + e.getMessage()); } } @@ -376,11 +397,16 @@ buffer.reset(); // Convert parameters for use in IESEngine - IESParameters params = new IESWithCipherParameters(engineSpec.getDerivationV(), + CipherParameters params = new IESWithCipherParameters(engineSpec.getDerivationV(), engineSpec.getEncodingV(), engineSpec.getMacKeySize(), engineSpec.getCipherKeySize()); + if (engineSpec.getNonce() != null) + { + params = new ParametersWithIV(params, engineSpec.getNonce()); + } + DHParameters dhParams = ((DHKeyParameters)key).getParameters(); byte[] V; @@ -400,7 +426,7 @@ } catch (Exception e) { - throw new BadPaddingException(e.getMessage()); + throw new BadBlockException("unable to process block", e); } } @@ -439,7 +465,7 @@ } catch (Exception e) { - throw new BadPaddingException(e.getMessage()); + throw new BadBlockException("unable to process block", e); } } else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE) @@ -453,7 +479,7 @@ } catch (InvalidCipherTextException e) { - throw new BadPaddingException(e.getMessage()); + throw new BadBlockException("unable to process block", e); } } else @@ -489,76 +515,32 @@ public IES() { super(new IESEngine(new DHBasicAgreement(), - new KDF2BytesGenerator(new SHA1Digest()), - new HMac(new SHA1Digest()))); + new KDF2BytesGenerator(DigestFactory.createSHA1()), + new HMac(DigestFactory.createSHA1()))); } } - static public class IESwithDESede + static public class IESwithDESedeCBC extends IESCipher { - public IESwithDESede() + public IESwithDESedeCBC() { super(new IESEngine(new DHBasicAgreement(), - new KDF2BytesGenerator(new SHA1Digest()), - new HMac(new SHA1Digest()), - new PaddedBufferedBlockCipher(new DESedeEngine()))); + new KDF2BytesGenerator(DigestFactory.createSHA1()), + new HMac(DigestFactory.createSHA1()), + new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESedeEngine()))), 8); } } - static public class IESwithAES + static public class IESwithAESCBC extends IESCipher { - public IESwithAES() + public IESwithAESCBC() { super(new IESEngine(new DHBasicAgreement(), - new KDF2BytesGenerator(new SHA1Digest()), - new HMac(new SHA1Digest()), - new PaddedBufferedBlockCipher(new AESEngine()))); - } - } - - /** - * Backwards compatibility. - */ - static public class OldIESwithCipher - extends IESCipher - { - public OldIESwithCipher(BlockCipher baseCipher) - { - super(new OldIESEngine(new DHBasicAgreement(), - new KDF2BytesGenerator(new SHA1Digest()), - new HMac(new SHA1Digest()), - new PaddedBufferedBlockCipher(baseCipher))); - } - } - - static public class OldIES - extends IESCipher - { - public OldIES() - { - super(new OldIESEngine(new DHBasicAgreement(), - new KDF2BytesGenerator(new SHA1Digest()), - new HMac(new SHA1Digest()))); - } - } - - static public class OldIESwithDESede - extends OldIESwithCipher - { - public OldIESwithDESede() - { - super(new DESedeEngine()); - } - } - - static public class OldIESwithAES - extends OldIESwithCipher - { - public OldIESwithAES() - { - super(new AESEngine()); + new KDF2BytesGenerator(DigestFactory.createSHA1()), + new HMac(DigestFactory.createSHA1()), + new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()))), 16); } } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java 2016-02-25 06:20:34.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java 2016-12-22 02:37:12.000000000 +0000 @@ -17,7 +17,7 @@ import org.bouncycastle.crypto.DerivationFunction; import org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator; -import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi; import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec; @@ -29,6 +29,9 @@ public class KeyAgreementSpi extends BaseAgreementSpi { + private static final BigInteger ONE = BigInteger.valueOf(1); + private static final BigInteger TWO = BigInteger.valueOf(2); + private BigInteger x; private BigInteger p; private BigInteger g; @@ -101,14 +104,22 @@ throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!"); } - if (lastPhase) + BigInteger peerY = ((DHPublicKey)key).getY(); + if (peerY == null || peerY.compareTo(TWO) < 0 + || peerY.compareTo(p.subtract(ONE)) >= 0) { - result = ((DHPublicKey)key).getY().modPow(x, p); - return null; + throw new InvalidKeyException("Invalid DH PublicKey"); } - else + + result = peerY.modPow(x, p); + if (result.compareTo(ONE) == 0) { - result = ((DHPublicKey)key).getY().modPow(x, p); + throw new InvalidKeyException("Shared key can't be 1"); + } + + if (lastPhase) + { + return null; } return new BCDHPublicKey(result, pubKey.getParams()); @@ -226,7 +237,7 @@ { public DHwithRFC2631KDF() { - super("DHwithRFC2631KDF", new DHKEKGenerator(new SHA1Digest())); + super("DHwithRFC2631KDF", new DHKEKGenerator(DigestFactory.createSHA1())); } } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java 2013-02-17 03:39:39.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java 2016-11-30 02:34:10.000000000 +0000 @@ -19,6 +19,7 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi; +import org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException; public class KeyFactorySpi extends BaseKeyFactorySpi @@ -82,7 +83,14 @@ { if (keySpec instanceof DHPublicKeySpec) { - return new BCDHPublicKey((DHPublicKeySpec)keySpec); + try + { + return new BCDHPublicKey((DHPublicKeySpec)keySpec); + } + catch (IllegalArgumentException e) + { + throw new ExtendedInvalidKeySpecException(e.getMessage(), e); + } } return super.engineGeneratePublic(keySpec); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java 2015-12-04 01:36:27.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java 2016-11-03 08:10:04.000000000 +0000 @@ -42,6 +42,7 @@ { this.strength = strength; this.random = random; + this.initialised = false; } public void initialize( @@ -113,7 +114,6 @@ DHPublicKeyParameters pub = (DHPublicKeyParameters)pair.getPublic(); DHPrivateKeyParameters priv = (DHPrivateKeyParameters)pair.getPrivate(); - return new KeyPair(new BCDHPublicKey(pub), - new BCDHPrivateKey(priv)); + return new KeyPair(new BCDHPublicKey(pub), new BCDHPrivateKey(priv)); } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java 2015-12-05 20:18:04.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java 2016-08-27 00:06:26.000000000 +0000 @@ -38,19 +38,14 @@ provider.addAlgorithm("AlgorithmParameterGenerator.DH", PREFIX + "AlgorithmParameterGeneratorSpi"); provider.addAlgorithm("Cipher.IES", PREFIX + "IESCipher$IES"); - provider.addAlgorithm("Cipher.IESwithAES", PREFIX + "IESCipher$IESwithAES"); - provider.addAlgorithm("Cipher.IESWITHAES", PREFIX + "IESCipher$IESwithAES"); - provider.addAlgorithm("Cipher.IESWITHDESEDE", PREFIX + "IESCipher$IESwithDESede"); + provider.addAlgorithm("Cipher.IESwithAES-CBC", PREFIX + "IESCipher$IESwithAESCBC"); + provider.addAlgorithm("Cipher.IESWITHAES-CBC", PREFIX + "IESCipher$IESwithAESCBC"); + provider.addAlgorithm("Cipher.IESWITHDESEDE-CBC", PREFIX + "IESCipher$IESwithDESedeCBC"); provider.addAlgorithm("Cipher.DHIES", PREFIX + "IESCipher$IES"); - provider.addAlgorithm("Cipher.DHIESwithAES", PREFIX + "IESCipher$IESwithAES"); - provider.addAlgorithm("Cipher.DHIESWITHAES", PREFIX + "IESCipher$IESwithAES"); - provider.addAlgorithm("Cipher.DHIESWITHDESEDE", PREFIX + "IESCipher$IESwithDESede"); - - provider.addAlgorithm("Cipher.OLDDHIES", PREFIX + "IESCipher$OldIES"); - provider.addAlgorithm("Cipher.OLDDHIESwithAES", PREFIX + "IESCipher$OldIESwithAES"); - provider.addAlgorithm("Cipher.OLDDHIESWITHAES", PREFIX + "IESCipher$OldIESwithAES"); - provider.addAlgorithm("Cipher.OLDDHIESWITHDESEDE", PREFIX + "IESCipher$OldIESwithDESede"); + provider.addAlgorithm("Cipher.DHIESwithAES-CBC", PREFIX + "IESCipher$IESwithAESCBC"); + provider.addAlgorithm("Cipher.DHIESWITHAES-CBC", PREFIX + "IESCipher$IESwithAESCBC"); + provider.addAlgorithm("Cipher.DHIESWITHDESEDE-CBC", PREFIX + "IESCipher$IESwithDESedeCBC"); registerOid(provider, PKCSObjectIdentifiers.dhKeyAgreement, "DH", new KeyFactorySpi()); registerOid(provider, X9ObjectIdentifiers.dhpublicnumber, "DH", new KeyFactorySpi()); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java 2015-04-26 02:17:47.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java 2016-12-20 01:53:07.000000000 +0000 @@ -24,15 +24,19 @@ implements DSAPublicKey { private static final long serialVersionUID = 1752452449903495175L; + private static BigInteger ZERO = BigInteger.valueOf(0); private BigInteger y; - private transient DSAParams dsaSpec; + + private transient DSAPublicKeyParameters lwKeyParams; + private transient DSAParams dsaSpec; BCDSAPublicKey( DSAPublicKeySpec spec) { this.y = spec.getY(); this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG()); + this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec)); } BCDSAPublicKey( @@ -40,27 +44,27 @@ { this.y = key.getY(); this.dsaSpec = key.getParams(); + this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec)); } BCDSAPublicKey( DSAPublicKeyParameters params) { this.y = params.getY(); - this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG()); - } - - BCDSAPublicKey( - BigInteger y, - DSAParameterSpec dsaSpec) - { - this.y = y; - this.dsaSpec = dsaSpec; + if (params != null) + { + this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG()); + } + else + { + this.dsaSpec = null; + } + this.lwKeyParams = params; } public BCDSAPublicKey( SubjectPublicKeyInfo info) { - ASN1Integer derY; try @@ -80,6 +84,12 @@ this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG()); } + else + { + this.dsaSpec = null; + } + + this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec)); } private boolean isNotNull(ASN1Encodable parameters) @@ -97,6 +107,11 @@ return "X.509"; } + DSAPublicKeyParameters engineGetKeyParameters() + { + return lwKeyParams; + } + public byte[] getEncoded() { if (dsaSpec == null) @@ -130,8 +145,15 @@ public int hashCode() { - return this.getY().hashCode() ^ this.getParams().getG().hashCode() + if (dsaSpec != null) + { + return this.getY().hashCode() ^ this.getParams().getG().hashCode() ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode(); + } + else + { + return this.getY().hashCode(); + } } public boolean equals( @@ -143,11 +165,19 @@ } DSAPublicKey other = (DSAPublicKey)o; - - return this.getY().equals(other.getY()) - && this.getParams().getG().equals(other.getParams().getG()) - && this.getParams().getP().equals(other.getParams().getP()) - && this.getParams().getQ().equals(other.getParams().getQ()); + + if (this.dsaSpec != null) + { + return this.getY().equals(other.getY()) + && other.getParams() != null + && this.getParams().getG().equals(other.getParams().getG()) + && this.getParams().getP().equals(other.getParams().getP()) + && this.getParams().getQ().equals(other.getParams().getQ()); + } + else + { + return this.getY().equals(other.getY()) && other.getParams() == null; + } } private void readObject( @@ -156,7 +186,16 @@ { in.defaultReadObject(); - this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject()); + BigInteger p = (BigInteger)in.readObject(); + if (p.equals(ZERO)) + { + this.dsaSpec = null; + } + else + { + this.dsaSpec = new DSAParameterSpec(p, (BigInteger)in.readObject(), (BigInteger)in.readObject()); + } + this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec)); } private void writeObject( @@ -165,8 +204,15 @@ { out.defaultWriteObject(); - out.writeObject(dsaSpec.getP()); - out.writeObject(dsaSpec.getQ()); - out.writeObject(dsaSpec.getG()); + if (dsaSpec == null) + { + out.writeObject(ZERO); + } + else + { + out.writeObject(dsaSpec.getP()); + out.writeObject(dsaSpec.getQ()); + out.writeObject(dsaSpec.getG()); + } } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java 2016-04-25 02:16:34.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java 2016-12-22 02:37:12.000000000 +0000 @@ -8,7 +8,6 @@ import java.security.SecureRandom; import java.security.SignatureException; import java.security.SignatureSpi; -import java.security.interfaces.DSAKey; import java.security.spec.AlgorithmParameterSpec; import org.bouncycastle.asn1.ASN1Encoding; @@ -17,20 +16,15 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DSA; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.NullDigest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA3Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import org.bouncycastle.crypto.util.DigestFactory; +import org.bouncycastle.util.Arrays; public class DSASigner extends SignatureSpi @@ -52,34 +46,7 @@ PublicKey publicKey) throws InvalidKeyException { - CipherParameters param; - - if (publicKey instanceof DSAKey) - { - param = DSAUtil.generatePublicKeyParameter(publicKey); - } - else - { - try - { - byte[] bytes = publicKey.getEncoded(); - - publicKey = new BCDSAPublicKey(SubjectPublicKeyInfo.getInstance(bytes)); - - if (publicKey instanceof DSAKey) - { - param = DSAUtil.generatePublicKeyParameter(publicKey); - } - else - { - throw new InvalidKeyException("can't recognise key type in DSA based signer"); - } - } - catch (Exception e) - { - throw new InvalidKeyException("can't recognise key type in DSA based signer"); - } - } + CipherParameters param = DSAUtil.generatePublicKeyParameter(publicKey); digest.reset(); signer.init(false, param); @@ -98,9 +65,7 @@ PrivateKey privateKey) throws InvalidKeyException { - CipherParameters param; - - param = DSAUtil.generatePrivateKeyParameter(privateKey); + CipherParameters param = DSAUtil.generatePrivateKeyParameter(privateKey); if (random != null) { @@ -207,6 +172,15 @@ throws IOException { ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); + if (s.size() != 2) + { + throw new IOException("malformed signature"); + } + if (!Arrays.areEqual(encoding, s.getEncoded(ASN1Encoding.DER))) + { + throw new IOException("malformed signature"); + } + return new BigInteger[]{ ((ASN1Integer)s.getObjectAt(0)).getValue(), ((ASN1Integer)s.getObjectAt(1)).getValue() @@ -218,7 +192,7 @@ { public stdDSA() { - super(new SHA1Digest(), new org.bouncycastle.crypto.signers.DSASigner()); + super(DigestFactory.createSHA1(), new org.bouncycastle.crypto.signers.DSASigner()); } } @@ -227,7 +201,7 @@ { public detDSA() { - super(new SHA1Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA1Digest()))); + super(DigestFactory.createSHA1(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1()))); } } @@ -236,7 +210,7 @@ { public dsa224() { - super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner()); + super(DigestFactory.createSHA224(), new org.bouncycastle.crypto.signers.DSASigner()); } } @@ -245,7 +219,7 @@ { public detDSA224() { - super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA224Digest()))); + super(DigestFactory.createSHA224(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224()))); } } @@ -254,7 +228,7 @@ { public dsa256() { - super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner()); + super(DigestFactory.createSHA256(), new org.bouncycastle.crypto.signers.DSASigner()); } } @@ -263,7 +237,7 @@ { public detDSA256() { - super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA256Digest()))); + super(DigestFactory.createSHA256(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256()))); } } @@ -272,7 +246,7 @@ { public dsa384() { - super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner()); + super(DigestFactory.createSHA384(), new org.bouncycastle.crypto.signers.DSASigner()); } } @@ -281,7 +255,7 @@ { public detDSA384() { - super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA384Digest()))); + super(DigestFactory.createSHA384(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384()))); } } @@ -290,7 +264,7 @@ { public dsa512() { - super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner()); + super(DigestFactory.createSHA512(), new org.bouncycastle.crypto.signers.DSASigner()); } } @@ -299,7 +273,7 @@ { public detDSA512() { - super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA512Digest()))); + super(DigestFactory.createSHA512(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512()))); } } @@ -308,7 +282,7 @@ { public dsaSha3_224() { - super(new SHA3Digest(224), new org.bouncycastle.crypto.signers.DSASigner()); + super(DigestFactory.createSHA3_224(), new org.bouncycastle.crypto.signers.DSASigner()); } } @@ -317,7 +291,7 @@ { public detDSASha3_224() { - super(new SHA3Digest(224), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA3Digest(224)))); + super(DigestFactory.createSHA3_224(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224()))); } } @@ -326,7 +300,7 @@ { public dsaSha3_256() { - super(new SHA3Digest(256), new org.bouncycastle.crypto.signers.DSASigner()); + super(DigestFactory.createSHA3_256(), new org.bouncycastle.crypto.signers.DSASigner()); } } @@ -335,7 +309,7 @@ { public detDSASha3_256() { - super(new SHA3Digest(256), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA3Digest(256)))); + super(DigestFactory.createSHA3_256(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256()))); } } @@ -344,7 +318,7 @@ { public dsaSha3_384() { - super(new SHA3Digest(384), new org.bouncycastle.crypto.signers.DSASigner()); + super(DigestFactory.createSHA3_384(), new org.bouncycastle.crypto.signers.DSASigner()); } } @@ -353,7 +327,7 @@ { public detDSASha3_384() { - super(new SHA3Digest(384), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA3Digest(384)))); + super(DigestFactory.createSHA3_384(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384()))); } } @@ -362,7 +336,7 @@ { public dsaSha3_512() { - super(new SHA3Digest(512), new org.bouncycastle.crypto.signers.DSASigner()); + super(DigestFactory.createSHA3_512(), new org.bouncycastle.crypto.signers.DSASigner()); } } @@ -371,7 +345,7 @@ { public detDSASha3_512() { - super(new SHA3Digest(512), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA3Digest(512)))); + super(DigestFactory.createSHA3_512(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512()))); } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java 2013-02-17 03:39:39.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java 2016-08-21 02:31:27.000000000 +0000 @@ -3,11 +3,14 @@ import java.security.InvalidKeyException; import java.security.PrivateKey; import java.security.PublicKey; +import java.security.interfaces.DSAParams; import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.DSAPublicKey; +import java.security.spec.DSAParameterSpec; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.DSAParameters; @@ -40,19 +43,42 @@ return false; } + static DSAParameters toDSAParameters(DSAParams spec) + { + if (spec != null) + { + return new DSAParameters(spec.getP(), spec.getQ(), spec.getG()); + } + + return null; + } + static public AsymmetricKeyParameter generatePublicKeyParameter( PublicKey key) throws InvalidKeyException { - if (key instanceof DSAPublicKey) + if (key instanceof BCDSAPublicKey) { - DSAPublicKey k = (DSAPublicKey)key; + return ((BCDSAPublicKey)key).engineGetKeyParameters(); + } - return new DSAPublicKeyParameters(k.getY(), - new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG())); + if (key instanceof DSAPublicKey) + { + return new BCDSAPublicKey((DSAPublicKey)key).engineGetKeyParameters(); } - throw new InvalidKeyException("can't identify DSA public key: " + key.getClass().getName()); + try + { + byte[] bytes = key.getEncoded(); + + BCDSAPublicKey bckey = new BCDSAPublicKey(SubjectPublicKeyInfo.getInstance(bytes)); + + return bckey.engineGetKeyParameters(); + } + catch (Exception e) + { + throw new InvalidKeyException("can't identify DSA public key: " + key.getClass().getName()); + } } static public AsymmetricKeyParameter generatePrivateKeyParameter( diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java 2013-02-17 03:39:39.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java 2016-08-21 03:24:11.000000000 +0000 @@ -109,7 +109,20 @@ { if (keySpec instanceof DSAPublicKeySpec) { - return new BCDSAPublicKey((DSAPublicKeySpec)keySpec); + try + { + return new BCDSAPublicKey((DSAPublicKeySpec)keySpec); + } + catch (final Exception e) + { + throw new InvalidKeySpecException("invalid KeySpec: " + e.getMessage()) + { + public Throwable getCause() + { + return e; + } + }; + } } return super.engineGeneratePublic(keySpec); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java 2014-03-21 02:39:25.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java 2016-11-03 23:04:18.000000000 +0000 @@ -6,18 +6,26 @@ import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.DSAParameterSpec; +import java.util.Hashtable; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.generators.DSAKeyPairGenerator; import org.bouncycastle.crypto.generators.DSAParametersGenerator; import org.bouncycastle.crypto.params.DSAKeyGenerationParameters; +import org.bouncycastle.crypto.params.DSAParameterGenerationParameters; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import org.bouncycastle.util.Integers; +import org.bouncycastle.util.Properties; public class KeyPairGeneratorSpi extends java.security.KeyPairGenerator { + private static Hashtable params = new Hashtable(); + private static Object lock = new Object(); + DSAKeyGenerationParameters param; DSAKeyPairGenerator engine = new DSAKeyPairGenerator(); int strength = 1024; @@ -41,6 +49,7 @@ this.strength = strength; this.random = random; + this.initialised = false; } public void initialize( @@ -64,10 +73,65 @@ { if (!initialised) { - DSAParametersGenerator pGen = new DSAParametersGenerator(); + Integer paramStrength = Integers.valueOf(strength); + + if (params.containsKey(paramStrength)) + { + param = (DSAKeyGenerationParameters)params.get(paramStrength); + } + else + { + synchronized (lock) + { + // we do the check again in case we were blocked by a generator for + // our key size. + if (params.containsKey(paramStrength)) + { + param = (DSAKeyGenerationParameters)params.get(paramStrength); + } + else + { + DSAParametersGenerator pGen; + DSAParameterGenerationParameters dsaParams; + + // Typical combination of keysize and size of q. + // keysize = 1024, q's size = 160 + // keysize = 2048, q's size = 224 + // keysize = 2048, q's size = 256 + // keysize = 3072, q's size = 256 + // For simplicity if keysize is greater than 1024 then we choose q's size to be 256. + // For legacy keysize that is less than 1024-bit, we just use the 186-2 style parameters + if (strength == 1024) + { + pGen = new DSAParametersGenerator(); + if (Properties.isOverrideSet("org.bouncycastle.dsa.FIPS186-2for1024bits")) + { + pGen.init(strength, certainty, random); + } + else + { + dsaParams = new DSAParameterGenerationParameters(1024, 160, certainty, random); + pGen.init(dsaParams); + } + } + else if (strength > 1024) + { + dsaParams = new DSAParameterGenerationParameters(strength, 256, certainty, random); + pGen = new DSAParametersGenerator(new SHA256Digest()); + pGen.init(dsaParams); + } + else + { + pGen = new DSAParametersGenerator(); + pGen.init(strength, certainty, random); + } + param = new DSAKeyGenerationParameters(random, pGen.generateParameters()); + + params.put(paramStrength, param); + } + } + } - pGen.init(strength, certainty, random); - param = new DSAKeyGenerationParameters(random, pGen.generateParameters()); engine.init(param); initialised = true; } @@ -76,7 +140,6 @@ DSAPublicKeyParameters pub = (DSAPublicKeyParameters)pair.getPublic(); DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)pair.getPrivate(); - return new KeyPair(new BCDSAPublicKey(pub), - new BCDSAPrivateKey(priv)); + return new KeyPair(new BCDSAPublicKey(pub), new BCDSAPrivateKey(priv)); } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java 2015-04-26 02:17:47.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java 2016-08-21 01:16:36.000000000 +0000 @@ -293,12 +293,12 @@ curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); } params = new X962Parameters(curveOid); - orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS()); + orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, ecSpec.getOrder(), this.getS()); } else if (ecSpec == null) { params = new X962Parameters(DERNull.INSTANCE); - orderBitLength = ECUtil.getOrderBitLength(null, this.getS()); + orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, null, this.getS()); } else { @@ -312,7 +312,7 @@ ecSpec.getCurve().getSeed()); params = new X962Parameters(ecP); - orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS()); + orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, ecSpec.getOrder(), this.getS()); } PrivateKeyInfo info; diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java 2015-06-07 11:13:20.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java 2016-08-21 23:38:49.000000000 +0000 @@ -30,7 +30,9 @@ import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; +import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import org.bouncycastle.jce.interfaces.ECPointEncoder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; @@ -48,14 +50,14 @@ private String algorithm = "DSTU4145"; private boolean withCompression; - private transient org.bouncycastle.math.ec.ECPoint q; + private transient ECPublicKeyParameters ecPublicKey; private transient ECParameterSpec ecSpec; private transient DSTU4145Params dstuParams; public BCDSTU4145PublicKey( BCDSTU4145PublicKey key) { - this.q = key.q; + this.ecPublicKey = key.ecPublicKey; this.ecSpec = key.ecSpec; this.withCompression = key.withCompression; this.dstuParams = key.dstuParams; @@ -65,29 +67,28 @@ ECPublicKeySpec spec) { this.ecSpec = spec.getParams(); - this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(null, ecSpec)); } public BCDSTU4145PublicKey( - org.bouncycastle.jce.spec.ECPublicKeySpec spec) + org.bouncycastle.jce.spec.ECPublicKeySpec spec, + ProviderConfiguration configuration) { - this.q = spec.getQ(); - if (spec.getParams() != null) // can be null if implictlyCa { ECCurve curve = spec.getParams().getCurve(); EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed()); + // this may seem a little long-winded but it's how we pick up the custom curve. + this.ecPublicKey = new ECPublicKeyParameters( + spec.getQ(), ECUtil.getDomainParameters(configuration, spec.getParams())); this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams()); } else { - if (q.getCurve() == null) - { - org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa(); - q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger()); - } + this.ecPublicKey = new ECPublicKeyParameters(s.getCurve().createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger()), EC5Util.getDomainParameters(configuration, (ECParameterSpec)null)); this.ecSpec = null; } } @@ -100,7 +101,7 @@ ECDomainParameters dp = params.getParameters(); this.algorithm = algorithm; - this.q = params.getQ(); + this.ecPublicKey = params; if (spec == null) { @@ -119,10 +120,9 @@ ECPublicKeyParameters params, org.bouncycastle.jce.spec.ECParameterSpec spec) { - ECDomainParameters dp = params.getParameters(); + ECDomainParameters dp = params.getParameters(); this.algorithm = algorithm; - this.q = params.getQ(); if (spec == null) { @@ -136,6 +136,8 @@ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec); } + + this.ecPublicKey = params; } /* @@ -146,7 +148,7 @@ ECPublicKeyParameters params) { this.algorithm = algorithm; - this.q = params.getQ(); + this.ecPublicKey = params; this.ecSpec = null; } @@ -161,14 +163,6 @@ dp.getH().intValue()); } - public BCDSTU4145PublicKey( - ECPublicKey key) - { - this.algorithm = key.getAlgorithm(); - this.ecSpec = key.getParams(); - this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false); - } - BCDSTU4145PublicKey( SubjectPublicKeyInfo info) { @@ -241,9 +235,6 @@ ECCurve curve = spec.getCurve(); EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed()); - //this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false); - this.q = DSTU4145PointEncoder.decodePoint(curve, keyEnc); - if (dstuParams.isNamedCurve()) { ecSpec = new ECNamedCurveSpec( @@ -263,6 +254,9 @@ spec.getG().getAffineYCoord().toBigInteger()), spec.getN(), spec.getH().intValue()); } + + //this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false); + this.ecPublicKey = new ECPublicKeyParameters(DSTU4145PointEncoder.decodePoint(curve, keyEnc), EC5Util.getDomainParameters(null, ecSpec)); } public byte[] getSbox() @@ -317,7 +311,7 @@ } } - byte[] encKey = DSTU4145PointEncoder.encodePoint(this.q); + byte[] encKey = DSTU4145PointEncoder.encodePoint(ecPublicKey.getQ()); try { @@ -348,11 +342,15 @@ public ECPoint getW() { + org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ(); + return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger()); } public org.bouncycastle.math.ec.ECPoint getQ() { + org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ(); + if (ecSpec == null) { return q.getDetachedPoint(); @@ -361,10 +359,10 @@ return q; } - public org.bouncycastle.math.ec.ECPoint engineGetQ() - { - return q; - } + ECPublicKeyParameters engineGetKeyParameters() + { + return ecPublicKey; + } org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() { @@ -382,8 +380,8 @@ String nl = Strings.lineSeparator(); buf.append("EC Public Key").append(nl); - buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl); - buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl); + buf.append(" X: ").append(getQ().getAffineXCoord().toBigInteger().toString(16)).append(nl); + buf.append(" Y: ").append(getQ().getAffineYCoord().toBigInteger().toString(16)).append(nl); return buf.toString(); } @@ -402,12 +400,12 @@ BCDSTU4145PublicKey other = (BCDSTU4145PublicKey)o; - return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec())); + return ecPublicKey.getQ().equals(other.ecPublicKey.getQ()) && (engineGetSpec().equals(other.engineGetSpec())); } public int hashCode() { - return engineGetQ().hashCode() ^ engineGetSpec().hashCode(); + return ecPublicKey.getQ().hashCode() ^ engineGetSpec().hashCode(); } private void readObject( diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java 2013-02-17 03:39:39.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java 2016-08-21 23:38:49.000000000 +0000 @@ -124,7 +124,7 @@ { if (keySpec instanceof ECPublicKeySpec) { - return new BCDSTU4145PublicKey((ECPublicKeySpec)keySpec); + return new BCDSTU4145PublicKey((ECPublicKeySpec)keySpec, BouncyCastleProvider.CONFIGURATION); } else if (keySpec instanceof java.security.spec.ECPublicKeySpec) { diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java 2015-06-07 11:13:20.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java 2016-09-12 09:55:35.000000000 +0000 @@ -75,7 +75,7 @@ ECParameterSpec p = (ECParameterSpec)params; this.ecParams = params; - param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random); + param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), random); engine.init(param); initialised = true; @@ -136,7 +136,7 @@ ECParameterSpec p = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); this.ecParams = params; - param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random); + param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), random); engine.init(param); initialised = true; diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java 2013-02-17 03:39:39.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java 2016-08-21 23:38:49.000000000 +0000 @@ -54,31 +54,13 @@ { CipherParameters param; - if (publicKey instanceof ECPublicKey) + if (publicKey instanceof BCDSTU4145PublicKey) { - param = ECUtil.generatePublicKeyParameter(publicKey); + param = ((BCDSTU4145PublicKey)publicKey).engineGetKeyParameters(); } else { - try - { - byte[] bytes = publicKey.getEncoded(); - - publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes)); - - if (publicKey instanceof ECPublicKey) - { - param = ECUtil.generatePublicKeyParameter(publicKey); - } - else - { - throw new InvalidKeyException("can't recognise key type in DSA based signer"); - } - } - catch (Exception e) - { - throw new InvalidKeyException("can't recognise key type in DSA based signer"); - } + param = ECUtil.generatePublicKeyParameter(publicKey); } digest = new GOST3411Digest(expandSbox(((BCDSTU4145PublicKey)publicKey).getSbox())); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java 2016-04-12 03:50:55.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java 2016-10-18 03:24:00.000000000 +0000 @@ -81,7 +81,13 @@ if (params.isNamedCurve()) { - curveName = ECNamedCurveTable.getName(ASN1ObjectIdentifier.getInstance(params.getParameters())); + ASN1ObjectIdentifier curveId = ASN1ObjectIdentifier.getInstance(params.getParameters()); + + curveName = ECNamedCurveTable.getName(curveId); + if (curveName == null) + { + curveName = curveId.getId(); + } } ecParameterSpec = EC5Util.convertToSpec(params, curve); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java 2015-06-23 01:28:32.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java 2016-10-18 07:01:23.000000000 +0000 @@ -17,12 +17,10 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X962Parameters; -import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; @@ -33,7 +31,6 @@ import org.bouncycastle.jce.interfaces.ECPointEncoder; import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.jce.spec.ECNamedCurveSpec; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.util.Strings; @@ -181,7 +178,14 @@ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec); } - publicKey = getPublicKeyDetails(pubKey); + try + { + publicKey = getPublicKeyDetails(pubKey); + } + catch (Exception e) + { + publicKey = null; // not all curves are encodable + } } public BCECPrivateKey( @@ -253,38 +257,16 @@ */ public byte[] getEncoded() { - X962Parameters params; - int orderBitLength; - - if (ecSpec instanceof ECNamedCurveSpec) - { - ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName()); - if (curveOid == null) // guess it's the OID - { - curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); - } + X962Parameters params = ECUtils.getDomainParametersFromName(ecSpec, withCompression); - params = new X962Parameters(curveOid); - orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS()); - } - else if (ecSpec == null) + int orderBitLength; + if (ecSpec == null) { - params = new X962Parameters(DERNull.INSTANCE); - orderBitLength = ECUtil.getOrderBitLength(null, this.getS()); + orderBitLength = ECUtil.getOrderBitLength(configuration, null, this.getS()); } else { - ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve()); - - X9ECParameters ecP = new X9ECParameters( - curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), - ecSpec.getOrder(), - BigInteger.valueOf(ecSpec.getCofactor()), - ecSpec.getCurve().getSeed()); - - params = new X962Parameters(ecP); - orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS()); + orderBitLength = ECUtil.getOrderBitLength(configuration, ecSpec.getOrder(), this.getS()); } PrivateKeyInfo info; @@ -420,9 +402,10 @@ byte[] enc = (byte[])in.readObject(); + this.configuration = BouncyCastleProvider.CONFIGURATION; + populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc))); - this.configuration = BouncyCastleProvider.CONFIGURATION; this.attrCarrier = new PKCS12BagAttributeCarrierImpl(); } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java 2015-06-23 01:43:42.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java 2016-10-18 07:50:57.000000000 +0000 @@ -3,7 +3,6 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.math.BigInteger; import java.security.interfaces.ECPublicKey; import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; @@ -11,16 +10,13 @@ import java.security.spec.EllipticCurve; import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X962Parameters; -import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ECPoint; import org.bouncycastle.asn1.x9.X9IntegerConverter; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; @@ -32,7 +28,6 @@ import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import org.bouncycastle.jce.interfaces.ECPointEncoder; import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.jce.spec.ECNamedCurveSpec; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.util.Strings; @@ -44,7 +39,7 @@ private String algorithm = "EC"; private boolean withCompression; - private transient org.bouncycastle.math.ec.ECPoint q; + private transient ECPublicKeyParameters ecPublicKey; private transient ECParameterSpec ecSpec; private transient ProviderConfiguration configuration; @@ -53,7 +48,7 @@ BCECPublicKey key) { this.algorithm = algorithm; - this.q = key.q; + this.ecPublicKey = key.ecPublicKey; this.ecSpec = key.ecSpec; this.withCompression = key.withCompression; this.configuration = key.configuration; @@ -66,7 +61,7 @@ { this.algorithm = algorithm; this.ecSpec = spec.getParams(); - this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(configuration, spec.getParams())); this.configuration = configuration; } @@ -76,7 +71,6 @@ ProviderConfiguration configuration) { this.algorithm = algorithm; - this.q = spec.getQ(); if (spec.getParams() != null) // can be null if implictlyCa { @@ -84,17 +78,15 @@ EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed()); // this may seem a little long-winded but it's how we pick up the custom curve. - this.q = EC5Util.convertCurve(ellipticCurve).createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger()); + this.ecPublicKey = new ECPublicKeyParameters( + spec.getQ(), ECUtil.getDomainParameters(configuration, spec.getParams())); this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams()); } else { - if (q.getCurve() == null) - { - org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa(); + org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa(); - q = s.getCurve().createPoint(q.getXCoord().toBigInteger(), q.getYCoord().toBigInteger(), false); - } + this.ecPublicKey = new ECPublicKeyParameters(s.getCurve().createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger()), EC5Util.getDomainParameters(configuration, (ECParameterSpec)null)); this.ecSpec = null; } @@ -110,7 +102,7 @@ ECDomainParameters dp = params.getParameters(); this.algorithm = algorithm; - this.q = params.getQ(); + this.ecPublicKey = params; if (spec == null) { @@ -149,8 +141,7 @@ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec); } - this.q = EC5Util.convertCurve(ecSpec.getCurve()).createPoint(params.getQ().getAffineXCoord().toBigInteger(), params.getQ().getAffineYCoord().toBigInteger()); - + this.ecPublicKey = params; this.configuration = configuration; } @@ -163,7 +154,7 @@ ProviderConfiguration configuration) { this.algorithm = algorithm; - this.q = params.getQ(); + this.ecPublicKey = params; this.ecSpec = null; this.configuration = configuration; } @@ -174,7 +165,7 @@ { this.algorithm = key.getAlgorithm(); this.ecSpec = key.getParams(); - this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW(), false), EC5Util.getDomainParameters(configuration, key.getParams())); } BCECPublicKey( @@ -200,7 +191,7 @@ private void populateFromPubKeyInfo(SubjectPublicKeyInfo info) { - X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithm().getParameters()); + X962Parameters params = X962Parameters.getInstance(info.getAlgorithm().getParameters()); ECCurve curve = EC5Util.getCurve(configuration, params); ecSpec = EC5Util.convertToSpec(params, curve); @@ -231,7 +222,7 @@ X9ECPoint derQ = new X9ECPoint(curve, key); - this.q = derQ.getPoint(); + this.ecPublicKey = new ECPublicKeyParameters(derQ.getPoint(), ECUtil.getDomainParameters(configuration, params)); } public String getAlgorithm() @@ -246,72 +237,15 @@ public byte[] getEncoded() { - ASN1Encodable params; - SubjectPublicKeyInfo info; - - if (ecSpec instanceof ECNamedCurveSpec) - { - ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName()); - if (curveOid == null) - { - curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); - } - params = new X962Parameters(curveOid); - } - else if (ecSpec == null) - { - params = new X962Parameters(DERNull.INSTANCE); - } - else - { - ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve()); - - X9ECParameters ecP = new X9ECParameters( - curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), - ecSpec.getOrder(), - BigInteger.valueOf(ecSpec.getCofactor()), - ecSpec.getCurve().getSeed()); - - params = new X962Parameters(ecP); - } - - ECCurve curve = this.engineGetQ().getCurve(); - ASN1OctetString p; + ASN1Encodable params = ECUtils.getDomainParametersFromName(ecSpec, withCompression); + ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(ecPublicKey.getQ(), withCompression).toASN1Primitive()); // stored curve is null if ImplicitlyCa - if (ecSpec == null) - { - p = (ASN1OctetString) - new X9ECPoint(curve.createPoint(this.getQ().getXCoord().toBigInteger(), this.getQ().getYCoord().toBigInteger(), withCompression)).toASN1Primitive(); - } - else - { - p = (ASN1OctetString) - new X9ECPoint(curve.createPoint(this.getQ().getAffineXCoord().toBigInteger(), this.getQ().getAffineYCoord().toBigInteger(), withCompression)).toASN1Primitive(); - } - - info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); return KeyUtil.getEncodedSubjectPublicKeyInfo(info); } - private void extractBytes(byte[] encKey, int offSet, BigInteger bI) - { - byte[] val = bI.toByteArray(); - if (val.length < 32) - { - byte[] tmp = new byte[32]; - System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length); - val = tmp; - } - - for (int i = 0; i != 32; i++) - { - encKey[offSet + i] = val[val.length - 1 - i]; - } - } - public ECParameterSpec getParams() { return ecSpec; @@ -329,11 +263,15 @@ public ECPoint getW() { + org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ(); + return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger()); } public org.bouncycastle.math.ec.ECPoint getQ() { + org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ(); + if (ecSpec == null) { return q.getDetachedPoint(); @@ -342,9 +280,9 @@ return q; } - public org.bouncycastle.math.ec.ECPoint engineGetQ() + ECPublicKeyParameters engineGetKeyParameters() { - return q; + return ecPublicKey; } org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() @@ -361,10 +299,11 @@ { StringBuffer buf = new StringBuffer(); String nl = Strings.lineSeparator(); + org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ(); buf.append("EC Public Key").append(nl); - buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl); - buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl); + buf.append(" X: ").append(q.getAffineXCoord().toBigInteger().toString(16)).append(nl); + buf.append(" Y: ").append(q.getAffineYCoord().toBigInteger().toString(16)).append(nl); return buf.toString(); @@ -384,12 +323,12 @@ BCECPublicKey other = (BCECPublicKey)o; - return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec())); + return ecPublicKey.getQ().equals(other.ecPublicKey.getQ()) && (engineGetSpec().equals(other.engineGetSpec())); } public int hashCode() { - return engineGetQ().hashCode() ^ engineGetSpec().hashCode(); + return ecPublicKey.getQ().hashCode() ^ engineGetSpec().hashCode(); } private void readObject( @@ -400,9 +339,9 @@ byte[] enc = (byte[])in.readObject(); - populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc))); - this.configuration = BouncyCastleProvider.CONFIGURATION; + + populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc))); } private void writeObject( diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java 2015-09-22 02:38:01.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java 2016-08-20 23:55:23.000000000 +0000 @@ -1,13 +1,30 @@ package org.bouncycastle.jcajce.provider.asymmetric.ec; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.PublicKey; import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import org.bouncycastle.jce.spec.ECNamedCurveSpec; +import org.bouncycastle.math.ec.ECCurve; class ECUtils { + static AsymmetricKeyParameter generatePublicKeyParameter( + PublicKey key) + throws InvalidKeyException + { + return (key instanceof BCECPublicKey) ? ((BCECPublicKey)key).engineGetKeyParameters() : ECUtil.generatePublicKeyParameter(key); + } + static X9ECParameters getDomainParametersFromGenSpec(ECGenParameterSpec genSpec) { return getDomainParametersFromName(genSpec.getName()); @@ -42,4 +59,38 @@ } return domainParameters; } + + static X962Parameters getDomainParametersFromName(ECParameterSpec ecSpec, boolean withCompression) + { + X962Parameters params; + + if (ecSpec instanceof ECNamedCurveSpec) + { + ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName()); + if (curveOid == null) + { + curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); + } + params = new X962Parameters(curveOid); + } + else if (ecSpec == null) + { + params = new X962Parameters(DERNull.INSTANCE); + } + else + { + ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve()); + + X9ECParameters ecP = new X9ECParameters( + curve, + EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), + ecSpec.getOrder(), + BigInteger.valueOf(ecSpec.getCofactor()), + ecSpec.getCurve().getSeed()); + + params = new X962Parameters(ecP); + } + + return params; + } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/IESCipher.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/IESCipher.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/IESCipher.java 2016-08-17 03:20:25.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/IESCipher.java 2016-12-22 02:37:12.000000000 +0000 @@ -23,11 +23,9 @@ import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.KeyEncoder; import org.bouncycastle.crypto.agreement.ECDHBasicAgreement; -import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.engines.DESedeEngine; import org.bouncycastle.crypto.engines.IESEngine; -import org.bouncycastle.crypto.engines.OldIESEngine; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; import org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator; import org.bouncycastle.crypto.generators.KDF2BytesGenerator; @@ -42,8 +40,10 @@ import org.bouncycastle.crypto.params.IESWithCipherParameters; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.crypto.parsers.ECIESPublicKeyParser; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.IESUtil; +import org.bouncycastle.jcajce.provider.util.BadBlockException; import org.bouncycastle.jcajce.util.BCJcaJceHelper; import org.bouncycastle.jcajce.util.JcaJceHelper; import org.bouncycastle.jce.interfaces.ECKey; @@ -108,6 +108,10 @@ public byte[] engineGetIV() { + if (engineSpec != null) + { + return engineSpec.getNonce(); + } return null; } @@ -264,7 +268,13 @@ // Use default parameters (including cipher key size) if none are specified if (engineSpec == null) { - this.engineSpec = IESUtil.guessParameterSpec(engine.getCipher()); + byte[] nonce = null; + if (ivLength != 0 && opmode == Cipher.ENCRYPT_MODE) + { + nonce = new byte[ivLength]; + random.nextBytes(nonce); + } + this.engineSpec = IESUtil.guessParameterSpec(engine.getCipher(), nonce); } else if (engineSpec instanceof IESParameterSpec) { @@ -277,16 +287,9 @@ byte[] nonce = this.engineSpec.getNonce(); - if (nonce != null) + if (ivLength != 0 && (nonce == null || nonce.length != ivLength)) { - if (ivLength == 0) - { - throw new InvalidAlgorithmParameterException("NONCE present in IES Parameters when none required"); - } - else if (nonce.length != ivLength) - { - throw new InvalidAlgorithmParameterException("NONCE in IES Parameters needs to be " + ivLength + " bytes long"); - } + throw new InvalidAlgorithmParameterException("NONCE in IES Parameters needs to be " + ivLength + " bytes long"); } // Parse the recipient's key @@ -294,13 +297,13 @@ { if (key instanceof PublicKey) { - this.key = ECUtil.generatePublicKeyParameter((PublicKey)key); + this.key = ECUtils.generatePublicKeyParameter((PublicKey)key); } else if (key instanceof IESKey) { IESKey ieKey = (IESKey)key; - this.key = ECUtil.generatePublicKeyParameter(ieKey.getPublic()); + this.key = ECUtils.generatePublicKeyParameter(ieKey.getPublic()); this.otherKeyParameter = ECUtil.generatePrivateKeyParameter(ieKey.getPrivate()); } else @@ -318,7 +321,7 @@ { IESKey ieKey = (IESKey)key; - this.otherKeyParameter = ECUtil.generatePublicKeyParameter(ieKey.getPublic()); + this.otherKeyParameter = ECUtils.generatePublicKeyParameter(ieKey.getPublic()); this.key = ECUtil.generatePrivateKeyParameter(ieKey.getPrivate()); } else @@ -351,7 +354,7 @@ } catch (InvalidAlgorithmParameterException e) { - throw new IllegalArgumentException("can't handle supplied parameter spec"); + throw new IllegalArgumentException("cannot handle supplied parameter spec: " + e.getMessage()); } } @@ -428,7 +431,7 @@ } catch (Exception e) { - throw new BadPaddingException(e.getMessage()); + throw new BadBlockException("unable to process block", e); } } @@ -454,11 +457,10 @@ return engine.processBlock(in, 0, in.length); } - catch (Exception e) + catch (final Exception e) { - throw new BadPaddingException(e.getMessage()); + throw new BadBlockException("unable to process block", e); } - } else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE) { @@ -471,7 +473,7 @@ } catch (InvalidCipherTextException e) { - throw new BadPaddingException(e.getMessage()); + throw new BadBlockException("unable to process block", e); } } else @@ -505,49 +507,23 @@ public ECIES() { super(new IESEngine(new ECDHBasicAgreement(), - new KDF2BytesGenerator(new SHA1Digest()), - new HMac(new SHA1Digest()))); + new KDF2BytesGenerator(DigestFactory.createSHA1()), + new HMac(DigestFactory.createSHA1()))); } } static public class ECIESwithCipher extends IESCipher { - public ECIESwithCipher(BlockCipher cipher) - { - super(new IESEngine(new ECDHBasicAgreement(), - new KDF2BytesGenerator(new SHA1Digest()), - new HMac(new SHA1Digest()), - new PaddedBufferedBlockCipher(cipher))); - } - public ECIESwithCipher(BlockCipher cipher, int ivLength) { super(new IESEngine(new ECDHBasicAgreement(), - new KDF2BytesGenerator(new SHA1Digest()), - new HMac(new SHA1Digest()), + new KDF2BytesGenerator(DigestFactory.createSHA1()), + new HMac(DigestFactory.createSHA1()), new PaddedBufferedBlockCipher(cipher)), ivLength); } } - static public class ECIESwithDESede - extends ECIESwithCipher - { - public ECIESwithDESede() - { - super(new DESedeEngine()); - } - } - - static public class ECIESwithAES - extends ECIESwithCipher - { - public ECIESwithAES() - { - super(new AESEngine()); - } - } - static public class ECIESwithDESedeCBC extends ECIESwithCipher { @@ -564,75 +540,5 @@ { super(new CBCBlockCipher(new AESEngine()), 16); } - } - - /** - * Backwards compatibility - */ - static public class OldECIES - extends IESCipher - { - public OldECIES() - { - super(new OldIESEngine(new ECDHBasicAgreement(), - new KDF2BytesGenerator(new SHA1Digest()), - new HMac(new SHA1Digest()))); - } - } - - static public class OldECIESwithCipher - extends IESCipher - { - public OldECIESwithCipher(BlockCipher baseCipher) - { - super(new OldIESEngine(new ECDHBasicAgreement(), - new KDF2BytesGenerator(new SHA1Digest()), - new HMac(new SHA1Digest()), - new PaddedBufferedBlockCipher(baseCipher))); - } - - public OldECIESwithCipher(BlockCipher baseCipher, int ivLength) - { - super(new OldIESEngine(new ECDHBasicAgreement(), - new KDF2BytesGenerator(new SHA1Digest()), - new HMac(new SHA1Digest()), - new PaddedBufferedBlockCipher(baseCipher)), ivLength); - } - } - - static public class OldECIESwithDESede - extends OldECIESwithCipher - { - public OldECIESwithDESede() - { - super(new DESedeEngine()); - } - } - - static public class OldECIESwithAES - extends OldECIESwithCipher - { - public OldECIESwithAES() - { - super(new AESEngine()); - } - } - - static public class OldECIESwithDESedeCBC - extends OldECIESwithCipher - { - public OldECIESwithDESedeCBC() - { - super(new CBCBlockCipher(new DESedeEngine()), 8); - } - } - - static public class OldECIESwithAESCBC - extends OldECIESwithCipher - { - public OldECIESwithAESCBC() - { - super(new CBCBlockCipher(new AESEngine()), 16); - } } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java 2016-02-25 06:20:34.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java 2016-12-22 00:46:13.000000000 +0000 @@ -17,17 +17,13 @@ import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement; import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement; import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.generators.KDF2BytesGenerator; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.params.MQVPrivateParameters; import org.bouncycastle.crypto.params.MQVPublicParameters; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jcajce.spec.MQVParameterSpec; @@ -94,9 +90,9 @@ if (!(key instanceof MQVPublicKey)) { ECPublicKeyParameters staticKey = (ECPublicKeyParameters) - ECUtil.generatePublicKeyParameter((PublicKey)key); + ECUtils.generatePublicKeyParameter((PublicKey)key); ECPublicKeyParameters ephemKey = (ECPublicKeyParameters) - ECUtil.generatePublicKeyParameter(mqvParameters.getOtherPartyEphemeralKey()); + ECUtils.generatePublicKeyParameter(mqvParameters.getOtherPartyEphemeralKey()); pubKey = new MQVPublicParameters(staticKey, ephemKey); } @@ -104,13 +100,11 @@ { MQVPublicKey mqvPubKey = (MQVPublicKey)key; ECPublicKeyParameters staticKey = (ECPublicKeyParameters) - ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey()); + ECUtils.generatePublicKeyParameter(mqvPubKey.getStaticKey()); ECPublicKeyParameters ephemKey = (ECPublicKeyParameters) - ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey()); + ECUtils.generatePublicKeyParameter(mqvPubKey.getEphemeralKey()); pubKey = new MQVPublicParameters(staticKey, ephemKey); - - // TODO Validate that all the keys are using the same parameters? } } else @@ -121,12 +115,23 @@ + getSimpleName(ECPublicKey.class) + " for doPhase"); } - pubKey = ECUtil.generatePublicKeyParameter((PublicKey)key); - - // TODO Validate that all the keys are using the same parameters? + pubKey = ECUtils.generatePublicKeyParameter((PublicKey)key); } - result = agreement.calculateAgreement(pubKey); + try + { + result = agreement.calculateAgreement(pubKey); + } + catch (final Exception e) + { + throw new InvalidKeyException("calculation failed: " + e.getMessage()) + { + public Throwable getCause() + { + return e; + } + }; + } return null; } @@ -180,7 +185,7 @@ if (mqvPrivKey.getEphemeralPublicKey() != null) { ephemPubKey = (ECPublicKeyParameters) - ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey()); + ECUtils.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey()); } } else @@ -196,7 +201,7 @@ if (mqvParameterSpec.getEphemeralPublicKey() != null) { ephemPubKey = (ECPublicKeyParameters) - ECUtil.generatePublicKeyParameter(mqvParameterSpec.getEphemeralPublicKey()); + ECUtils.generatePublicKeyParameter(mqvParameterSpec.getEphemeralPublicKey()); } mqvParameters = mqvParameterSpec; ukmParameters = mqvParameterSpec.getUserKeyingMaterial(); @@ -269,7 +274,7 @@ { public DHwithSHA1KDF() { - super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest())); + super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); } } @@ -278,7 +283,7 @@ { public DHwithSHA1KDFAndSharedInfo() { - super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest())); + super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); } } @@ -287,7 +292,7 @@ { public CDHwithSHA1KDFAndSharedInfo() { - super("ECCDHwithSHA1KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest())); + super("ECCDHwithSHA1KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); } } @@ -296,7 +301,7 @@ { public DHwithSHA224KDFAndSharedInfo() { - super("ECDHwithSHA224KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA224Digest())); + super("ECDHwithSHA224KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224())); } } @@ -305,7 +310,7 @@ { public CDHwithSHA224KDFAndSharedInfo() { - super("ECCDHwithSHA224KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA224Digest())); + super("ECCDHwithSHA224KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224())); } } @@ -314,7 +319,7 @@ { public DHwithSHA256KDFAndSharedInfo() { - super("ECDHwithSHA256KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA256Digest())); + super("ECDHwithSHA256KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256())); } } @@ -323,7 +328,7 @@ { public CDHwithSHA256KDFAndSharedInfo() { - super("ECCDHwithSHA256KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA256Digest())); + super("ECCDHwithSHA256KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256())); } } @@ -332,7 +337,7 @@ { public DHwithSHA384KDFAndSharedInfo() { - super("ECDHwithSHA384KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA384Digest())); + super("ECDHwithSHA384KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384())); } } @@ -341,7 +346,7 @@ { public CDHwithSHA384KDFAndSharedInfo() { - super("ECCDHwithSHA384KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA384Digest())); + super("ECCDHwithSHA384KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384())); } } @@ -350,7 +355,7 @@ { public DHwithSHA512KDFAndSharedInfo() { - super("ECDHwithSHA512KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA512Digest())); + super("ECDHwithSHA512KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); } } @@ -359,7 +364,7 @@ { public CDHwithSHA512KDFAndSharedInfo() { - super("ECCDHwithSHA512KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA512Digest())); + super("ECCDHwithSHA512KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); } } @@ -368,7 +373,7 @@ { public MQVwithSHA1KDFAndSharedInfo() { - super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest())); + super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); } } @@ -377,7 +382,7 @@ { public MQVwithSHA224KDFAndSharedInfo() { - super("ECMQVwithSHA224KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA224Digest())); + super("ECMQVwithSHA224KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224())); } } @@ -386,7 +391,7 @@ { public MQVwithSHA256KDFAndSharedInfo() { - super("ECMQVwithSHA256KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA256Digest())); + super("ECMQVwithSHA256KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256())); } } @@ -395,7 +400,7 @@ { public MQVwithSHA384KDFAndSharedInfo() { - super("ECMQVwithSHA384KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA384Digest())); + super("ECMQVwithSHA384KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384())); } } @@ -404,7 +409,7 @@ { public MQVwithSHA512KDFAndSharedInfo() { - super("ECMQVwithSHA512KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA512Digest())); + super("ECMQVwithSHA512KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); } } @@ -413,7 +418,7 @@ { public DHwithSHA1CKDF() { - super("ECDHwithSHA1CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA1Digest())); + super("ECDHwithSHA1CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1())); } } @@ -422,7 +427,7 @@ { public DHwithSHA256CKDF() { - super("ECDHwithSHA256CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA256Digest())); + super("ECDHwithSHA256CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256())); } } @@ -431,7 +436,7 @@ { public DHwithSHA384CKDF() { - super("ECDHwithSHA384CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA384Digest())); + super("ECDHwithSHA384CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384())); } } @@ -440,7 +445,7 @@ { public DHwithSHA512CKDF() { - super("ECDHwithSHA512CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA512Digest())); + super("ECDHwithSHA512CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512())); } } @@ -449,7 +454,7 @@ { public MQVwithSHA1CKDF() { - super("ECMQVwithSHA1CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA1Digest())); + super("ECMQVwithSHA1CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1())); } } @@ -458,7 +463,7 @@ { public MQVwithSHA224CKDF() { - super("ECMQVwithSHA224CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA224Digest())); + super("ECMQVwithSHA224CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA224())); } } @@ -467,7 +472,7 @@ { public MQVwithSHA256CKDF() { - super("ECMQVwithSHA256CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA256Digest())); + super("ECMQVwithSHA256CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256())); } } @@ -476,7 +481,7 @@ { public MQVwithSHA384CKDF() { - super("ECMQVwithSHA384CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA384Digest())); + super("ECMQVwithSHA384CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384())); } } @@ -485,7 +490,7 @@ { public MQVwithSHA512CKDF() { - super("ECMQVwithSHA512CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA512Digest())); + super("ECMQVwithSHA512CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512())); } } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java 2015-03-26 00:21:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java 2016-08-20 22:36:30.000000000 +0000 @@ -141,13 +141,20 @@ KeySpec keySpec) throws InvalidKeySpecException { - if (keySpec instanceof ECPublicKeySpec) + try { - return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration); + if (keySpec instanceof ECPublicKeySpec) + { + return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration); + } + else if (keySpec instanceof java.security.spec.ECPublicKeySpec) + { + return new BCECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec, configuration); + } } - else if (keySpec instanceof java.security.spec.ECPublicKeySpec) + catch (Exception e) { - return new BCECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec, configuration); + throw new InvalidKeySpecException("invalid KeySpec: " + e.getMessage(), e); } return super.engineGeneratePublic(keySpec); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java 2015-09-22 02:38:01.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java 2016-10-18 03:35:12.000000000 +0000 @@ -8,6 +8,7 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECGenParameterSpec; import java.util.Hashtable; +import java.util.Map; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.x9.ECNamedCurveTable; @@ -181,7 +182,7 @@ protected ECKeyGenerationParameters createKeyGenParamsBC(ECParameterSpec p, SecureRandom r) { - return new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), r); + return new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), r); } protected ECKeyGenerationParameters createKeyGenParamsJCE(java.security.spec.ECParameterSpec p, SecureRandom r) @@ -208,7 +209,14 @@ p = ECNamedCurveTable.getByOID(new ASN1ObjectIdentifier(curveName)); if (p == null) { - throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName); + Map extraCurves = configuration.getAdditionalECParameters(); + + p = (X9ECParameters)extraCurves.get(new ASN1ObjectIdentifier(curveName)); + + if (p == null) + { + throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName); + } } } catch (IllegalArgumentException ex) diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java 2016-04-25 00:58:34.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java 2016-12-22 02:07:48.000000000 +0000 @@ -17,19 +17,15 @@ import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.NullDigest; import org.bouncycastle.crypto.digests.RIPEMD160Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA3Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.signers.ECDSASigner; import org.bouncycastle.crypto.signers.ECNRSigner; import org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.jcajce.provider.asymmetric.util.DSABase; import org.bouncycastle.jcajce.provider.asymmetric.util.DSAEncoder; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import org.bouncycastle.util.Arrays; public class SignatureSpi extends DSABase @@ -42,7 +38,7 @@ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { - CipherParameters param = ECUtil.generatePublicKeyParameter(publicKey); + CipherParameters param = ECUtils.generatePublicKeyParameter(publicKey); digest.reset(); signer.init(false, param); @@ -71,7 +67,7 @@ { public ecDSA() { - super(new SHA1Digest(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA1(), new ECDSASigner(), new StdDSAEncoder()); } } @@ -80,7 +76,7 @@ { public ecDetDSA() { - super(new SHA1Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA1Digest())), new StdDSAEncoder()); + super(DigestFactory.createSHA1(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1())), new StdDSAEncoder()); } } @@ -98,7 +94,7 @@ { public ecDSA224() { - super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA224(), new ECDSASigner(), new StdDSAEncoder()); } } @@ -107,7 +103,7 @@ { public ecDetDSA224() { - super(new SHA224Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA224Digest())), new StdDSAEncoder()); + super(DigestFactory.createSHA224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224())), new StdDSAEncoder()); } } @@ -116,7 +112,7 @@ { public ecDSA256() { - super(new SHA256Digest(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA256(), new ECDSASigner(), new StdDSAEncoder()); } } @@ -125,7 +121,7 @@ { public ecDetDSA256() { - super(new SHA256Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest())), new StdDSAEncoder()); + super(DigestFactory.createSHA256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256())), new StdDSAEncoder()); } } @@ -134,7 +130,7 @@ { public ecDSA384() { - super(new SHA384Digest(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA384(), new ECDSASigner(), new StdDSAEncoder()); } } @@ -143,7 +139,7 @@ { public ecDetDSA384() { - super(new SHA384Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA384Digest())), new StdDSAEncoder()); + super(DigestFactory.createSHA384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384())), new StdDSAEncoder()); } } @@ -152,7 +148,7 @@ { public ecDSA512() { - super(new SHA512Digest(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA512(), new ECDSASigner(), new StdDSAEncoder()); } } @@ -161,7 +157,7 @@ { public ecDetDSA512() { - super(new SHA512Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA512Digest())), new StdDSAEncoder()); + super(DigestFactory.createSHA512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512())), new StdDSAEncoder()); } } @@ -170,7 +166,7 @@ { public ecDSASha3_224() { - super(new SHA3Digest(224), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_224(), new ECDSASigner(), new StdDSAEncoder()); } } @@ -179,7 +175,7 @@ { public ecDetDSASha3_224() { - super(new SHA3Digest(224), new ECDSASigner(new HMacDSAKCalculator(new SHA3Digest(224))), new StdDSAEncoder()); + super(DigestFactory.createSHA3_224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224())), new StdDSAEncoder()); } } @@ -188,7 +184,7 @@ { public ecDSASha3_256() { - super(new SHA3Digest(256), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_256(), new ECDSASigner(), new StdDSAEncoder()); } } @@ -197,7 +193,7 @@ { public ecDetDSASha3_256() { - super(new SHA3Digest(256), new ECDSASigner(new HMacDSAKCalculator(new SHA3Digest(256))), new StdDSAEncoder()); + super(DigestFactory.createSHA3_256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256())), new StdDSAEncoder()); } } @@ -206,7 +202,7 @@ { public ecDSASha3_384() { - super(new SHA3Digest(384), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_384(), new ECDSASigner(), new StdDSAEncoder()); } } @@ -215,7 +211,7 @@ { public ecDetDSASha3_384() { - super(new SHA3Digest(384), new ECDSASigner(new HMacDSAKCalculator(new SHA3Digest(384))), new StdDSAEncoder()); + super(DigestFactory.createSHA3_384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384())), new StdDSAEncoder()); } } @@ -224,7 +220,7 @@ { public ecDSASha3_512() { - super(new SHA3Digest(512), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_512(), new ECDSASigner(), new StdDSAEncoder()); } } @@ -233,7 +229,7 @@ { public ecDetDSASha3_512() { - super(new SHA3Digest(512), new ECDSASigner(new HMacDSAKCalculator(new SHA3Digest(512))), new StdDSAEncoder()); + super(DigestFactory.createSHA3_512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512())), new StdDSAEncoder()); } } @@ -251,7 +247,7 @@ { public ecNR() { - super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA1(), new ECNRSigner(), new StdDSAEncoder()); } } @@ -260,7 +256,7 @@ { public ecNR224() { - super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA224(), new ECNRSigner(), new StdDSAEncoder()); } } @@ -269,7 +265,7 @@ { public ecNR256() { - super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA256(), new ECNRSigner(), new StdDSAEncoder()); } } @@ -278,7 +274,7 @@ { public ecNR384() { - super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA384(), new ECNRSigner(), new StdDSAEncoder()); } } @@ -287,7 +283,7 @@ { public ecNR512() { - super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA512(), new ECNRSigner(), new StdDSAEncoder()); } } @@ -296,7 +292,7 @@ { public ecCVCDSA() { - super(new SHA1Digest(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA1(), new ECDSASigner(), new PlainDSAEncoder()); } } @@ -305,7 +301,7 @@ { public ecCVCDSA224() { - super(new SHA224Digest(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA224(), new ECDSASigner(), new PlainDSAEncoder()); } } @@ -314,7 +310,7 @@ { public ecCVCDSA256() { - super(new SHA256Digest(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA256(), new ECDSASigner(), new PlainDSAEncoder()); } } @@ -323,7 +319,7 @@ { public ecCVCDSA384() { - super(new SHA384Digest(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA384(), new ECDSASigner(), new PlainDSAEncoder()); } } @@ -332,7 +328,7 @@ { public ecCVCDSA512() { - super(new SHA512Digest(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA512(), new ECDSASigner(), new PlainDSAEncoder()); } } @@ -366,6 +362,15 @@ throws IOException { ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); + if (s.size() != 2) + { + throw new IOException("malformed signature"); + } + if (!Arrays.areEqual(encoding, s.getEncoded(ASN1Encoding.DER))) + { + throw new IOException("malformed signature"); + } + BigInteger[] sig = new BigInteger[2]; sig[0] = ASN1Integer.getInstance(s.getObjectAt(0)).getValue(); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java 2015-05-27 01:03:47.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java 2016-08-21 01:16:54.000000000 +0000 @@ -366,12 +366,12 @@ curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); } params = new X962Parameters(curveOid); - orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS()); + orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, ecSpec.getOrder(), this.getS()); } else if (ecSpec == null) { params = new X962Parameters(DERNull.INSTANCE); - orderBitLength = ECUtil.getOrderBitLength(null, this.getS()); + orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, null, this.getS()); } else { @@ -385,7 +385,7 @@ ecSpec.getCurve().getSeed()); params = new X962Parameters(ecP); - orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS()); + orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, ecSpec.getOrder(), this.getS()); } PrivateKeyInfo info; diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java 2015-04-26 02:17:46.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java 2016-08-21 23:06:27.000000000 +0000 @@ -25,15 +25,15 @@ import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; +import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import org.bouncycastle.jce.ECGOST3410NamedCurveTable; import org.bouncycastle.jce.interfaces.ECPointEncoder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import org.bouncycastle.jce.spec.ECNamedCurveSpec; import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.math.ec.custom.sec.SecP256K1Point; -import org.bouncycastle.math.ec.custom.sec.SecP256R1Point; import org.bouncycastle.util.Strings; public class BCECGOST3410PublicKey @@ -44,14 +44,14 @@ private String algorithm = "ECGOST3410"; private boolean withCompression; - private transient org.bouncycastle.math.ec.ECPoint q; + private transient ECPublicKeyParameters ecPublicKey; private transient ECParameterSpec ecSpec; private transient GOST3410PublicKeyAlgParameters gostParams; public BCECGOST3410PublicKey( BCECGOST3410PublicKey key) { - this.q = key.q; + this.ecPublicKey = key.ecPublicKey; this.ecSpec = key.ecSpec; this.withCompression = key.withCompression; this.gostParams = key.gostParams; @@ -61,29 +61,28 @@ ECPublicKeySpec spec) { this.ecSpec = spec.getParams(); - this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(null, spec.getParams())); } public BCECGOST3410PublicKey( - org.bouncycastle.jce.spec.ECPublicKeySpec spec) + org.bouncycastle.jce.spec.ECPublicKeySpec spec, + ProviderConfiguration configuration) { - this.q = spec.getQ(); - if (spec.getParams() != null) // can be null if implictlyCa { ECCurve curve = spec.getParams().getCurve(); EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed()); + // this may seem a little long-winded but it's how we pick up the custom curve. + this.ecPublicKey = new ECPublicKeyParameters( + spec.getQ(), ECUtil.getDomainParameters(configuration, spec.getParams())); this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams()); } else { - if (q.getCurve() == null) - { - org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa(); - q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger()); - } + this.ecPublicKey = new ECPublicKeyParameters(s.getCurve().createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger()), EC5Util.getDomainParameters(configuration, (ECParameterSpec)null)); this.ecSpec = null; } } @@ -93,10 +92,10 @@ ECPublicKeyParameters params, ECParameterSpec spec) { - ECDomainParameters dp = params.getParameters(); + ECDomainParameters dp = params.getParameters(); this.algorithm = algorithm; - this.q = params.getQ(); + this.ecPublicKey = params; if (spec == null) { @@ -118,7 +117,7 @@ ECDomainParameters dp = params.getParameters(); this.algorithm = algorithm; - this.q = params.getQ(); + this.ecPublicKey = params; if (spec == null) { @@ -142,7 +141,7 @@ ECPublicKeyParameters params) { this.algorithm = algorithm; - this.q = params.getQ(); + this.ecPublicKey = params; this.ecSpec = null; } @@ -162,7 +161,7 @@ { this.algorithm = key.getAlgorithm(); this.ecSpec = key.getParams(); - this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW(), false), EC5Util.getDomainParameters(null, key.getParams())); } BCECGOST3410PublicKey( @@ -207,7 +206,7 @@ ECCurve curve = spec.getCurve(); EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed()); - this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y)); + this.ecPublicKey = new ECPublicKeyParameters(curve.createPoint(new BigInteger(1, x), new BigInteger(1, y)), ECUtil.getDomainParameters(null, spec)); ecSpec = new ECNamedCurveSpec( ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()), @@ -260,8 +259,8 @@ } } - BigInteger bX = this.q.getAffineXCoord().toBigInteger(); - BigInteger bY = this.q.getAffineYCoord().toBigInteger(); + BigInteger bX = this.ecPublicKey.getQ().getAffineXCoord().toBigInteger(); + BigInteger bY = this.ecPublicKey.getQ().getAffineYCoord().toBigInteger(); byte[] encKey = new byte[64]; extractBytes(encKey, 0, bX); @@ -312,22 +311,22 @@ public ECPoint getW() { - return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger()); + return new ECPoint(ecPublicKey.getQ().getAffineXCoord().toBigInteger(), ecPublicKey.getQ().getAffineYCoord().toBigInteger()); } public org.bouncycastle.math.ec.ECPoint getQ() { if (ecSpec == null) { - return q.getDetachedPoint(); + return ecPublicKey.getQ().getDetachedPoint(); } - return q; + return ecPublicKey.getQ(); } - public org.bouncycastle.math.ec.ECPoint engineGetQ() + ECPublicKeyParameters engineGetKeyParameters() { - return q; + return ecPublicKey; } org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() @@ -344,10 +343,11 @@ { StringBuffer buf = new StringBuffer(); String nl = Strings.lineSeparator(); + org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ(); buf.append("EC Public Key").append(nl); - buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl); - buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl); + buf.append(" X: ").append(q.getAffineXCoord().toBigInteger().toString(16)).append(nl); + buf.append(" Y: ").append(q.getAffineYCoord().toBigInteger().toString(16)).append(nl); return buf.toString(); } @@ -366,12 +366,12 @@ BCECGOST3410PublicKey other = (BCECGOST3410PublicKey)o; - return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec())); + return ecPublicKey.getQ().equals(other.ecPublicKey.getQ()) && (engineGetSpec().equals(other.engineGetSpec())); } public int hashCode() { - return engineGetQ().hashCode() ^ engineGetSpec().hashCode(); + return ecPublicKey.getQ().hashCode() ^ engineGetSpec().hashCode(); } private void readObject( diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java 2013-02-17 03:39:39.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java 2016-08-21 22:44:48.000000000 +0000 @@ -124,7 +124,7 @@ { if (keySpec instanceof ECPublicKeySpec) { - return new BCECGOST3410PublicKey((ECPublicKeySpec)keySpec); + return new BCECGOST3410PublicKey((ECPublicKeySpec)keySpec, BouncyCastleProvider.CONFIGURATION); } else if (keySpec instanceof java.security.spec.ECPublicKeySpec) { diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java 2013-02-17 03:39:39.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java 2016-09-12 10:07:26.000000000 +0000 @@ -74,7 +74,7 @@ ECParameterSpec p = (ECParameterSpec)params; this.ecParams = params; - param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random); + param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), random); engine.init(param); initialised = true; @@ -134,7 +134,7 @@ ECParameterSpec p = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); this.ecParams = params; - param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random); + param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), random); engine.init(param); initialised = true; diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java 2015-01-31 23:34:17.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java 2016-08-21 23:07:33.000000000 +0000 @@ -14,14 +14,15 @@ import org.bouncycastle.crypto.DSA; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.GOST3411Digest; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.signers.ECGOST3410Signer; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import org.bouncycastle.jcajce.provider.asymmetric.util.GOST3410Util; import org.bouncycastle.jce.interfaces.ECKey; import org.bouncycastle.jce.interfaces.ECPublicKey; import org.bouncycastle.jce.interfaces.GOST3410Key; import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.jcajce.provider.asymmetric.util.GOST3410Util; public class SignatureSpi extends java.security.SignatureSpi @@ -44,7 +45,7 @@ if (publicKey instanceof ECPublicKey) { - param = ECUtil.generatePublicKeyParameter(publicKey); + param = generatePublicKeyParameter(publicKey); } else if (publicKey instanceof GOST3410Key) { @@ -208,4 +209,11 @@ { throw new UnsupportedOperationException("engineSetParameter unsupported"); } + + static AsymmetricKeyParameter generatePublicKeyParameter( + PublicKey key) + throws InvalidKeyException + { + return (key instanceof BCECGOST3410PublicKey) ? ((BCECGOST3410PublicKey)key).engineGetKeyParameters() : ECUtil.generatePublicKeyParameter(key); + } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java 2016-04-25 00:54:33.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java 2016-08-27 00:06:26.000000000 +0000 @@ -134,25 +134,12 @@ provider.addAlgorithm("KeyPairGenerator.ECIES", PREFIX + "KeyPairGeneratorSpi$ECDH"); provider.addAlgorithm("Cipher.ECIES", PREFIX + "IESCipher$ECIES"); - provider.addAlgorithm("Cipher.ECIESwithAES", PREFIX + "IESCipher$ECIESwithAES"); - provider.addAlgorithm("Cipher.ECIESWITHAES", PREFIX + "IESCipher$ECIESwithAES"); - provider.addAlgorithm("Cipher.ECIESwithDESEDE", PREFIX + "IESCipher$ECIESwithDESede"); - provider.addAlgorithm("Cipher.ECIESWITHDESEDE", PREFIX + "IESCipher$ECIESwithDESede"); + provider.addAlgorithm("Cipher.ECIESwithAES-CBC", PREFIX + "IESCipher$ECIESwithAESCBC"); provider.addAlgorithm("Cipher.ECIESWITHAES-CBC", PREFIX + "IESCipher$ECIESwithAESCBC"); provider.addAlgorithm("Cipher.ECIESwithDESEDE-CBC", PREFIX + "IESCipher$ECIESwithDESedeCBC"); provider.addAlgorithm("Cipher.ECIESWITHDESEDE-CBC", PREFIX + "IESCipher$ECIESwithDESedeCBC"); - provider.addAlgorithm("Cipher.OldECIES", PREFIX + "IESCipher$OldECIES"); - provider.addAlgorithm("Cipher.OldECIESwithAES", PREFIX + "IESCipher$OldECIESwithAES"); - provider.addAlgorithm("Cipher.OldECIESWITHAES", PREFIX + "IESCipher$OldECIESwithAES"); - provider.addAlgorithm("Cipher.OldECIESwithDESEDE", PREFIX + "IESCipher$OldECIESwithDESede"); - provider.addAlgorithm("Cipher.OldECIESWITHDESEDE", PREFIX + "IESCipher$OldECIESwithDESede"); - provider.addAlgorithm("Cipher.OldECIESwithAES-CBC", PREFIX + "IESCipher$OldECIESwithAESCBC"); - provider.addAlgorithm("Cipher.OldECIESWITHAES-CBC", PREFIX + "IESCipher$OldECIESwithAESCBC"); - provider.addAlgorithm("Cipher.OldECIESwithDESEDE-CBC", PREFIX + "IESCipher$OldECIESwithDESedeCBC"); - provider.addAlgorithm("Cipher.OldECIESWITHDESEDE-CBC", PREFIX + "IESCipher$OldECIESwithDESedeCBC"); - provider.addAlgorithm("Signature.ECDSA", PREFIX + "SignatureSpi$ecDSA"); provider.addAlgorithm("Signature.NONEwithECDSA", PREFIX + "SignatureSpi$ecDSAnone"); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java 2015-02-14 03:20:28.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java 2016-12-20 05:26:26.000000000 +0000 @@ -30,6 +30,7 @@ import org.bouncycastle.crypto.engines.ElGamalEngine; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseCipherSpi; +import org.bouncycastle.jcajce.provider.util.BadBlockException; import org.bouncycastle.jcajce.provider.util.DigestFactory; import org.bouncycastle.jce.interfaces.ElGamalKey; import org.bouncycastle.jce.interfaces.ElGamalPrivateKey; @@ -277,14 +278,8 @@ throws IllegalBlockSizeException, BadPaddingException { cipher.processBytes(input, inputOffset, inputLen); - try - { - return cipher.doFinal(); - } - catch (InvalidCipherTextException e) - { - throw new BadPaddingException(e.getMessage()); - } + + return getOutput(); } protected int engineDoFinal( @@ -295,18 +290,9 @@ int outputOffset) throws IllegalBlockSizeException, BadPaddingException { - byte[] out; - cipher.processBytes(input, inputOffset, inputLen); - try - { - out = cipher.doFinal(); - } - catch (InvalidCipherTextException e) - { - throw new BadPaddingException(e.getMessage()); - } + byte[] out = getOutput(); for (int i = 0; i != out.length; i++) { @@ -316,6 +302,29 @@ return out.length; } + private byte[] getOutput() + throws BadPaddingException + { + try + { + return cipher.doFinal(); + } + catch (final InvalidCipherTextException e) + { + throw new BadPaddingException("unable to decrypt block") + { + public synchronized Throwable getCause() + { + return e; + } + }; + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new BadBlockException("unable to decrypt block", e); + } + } + /** * classes that inherit from us. */ diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java 2016-02-24 12:05:50.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java 2016-08-27 01:41:24.000000000 +0000 @@ -57,7 +57,15 @@ v.add(new DERTaggedObject(false, 1, new DEROctetString(currentSpec.getEncodingV()))); } v.add(new ASN1Integer(currentSpec.getMacKeySize())); + if (currentSpec.getNonce() != null) + { + ASN1EncodableVector cV = new ASN1EncodableVector(); + + cV.add(new ASN1Integer(currentSpec.getCipherKeySize())); + cV.add(new ASN1Integer(currentSpec.getNonce())); + v.add(new DERSequence(cV)); + } return new DERSequence(v).getEncoded(ASN1Encoding.DER); } catch (IOException e) @@ -126,13 +134,23 @@ this.currentSpec = new IESParameterSpec(null, ASN1OctetString.getInstance(tagged, false).getOctets(), ASN1Integer.getInstance(s.getObjectAt(1)).getValue().intValue()); } } - else + else if (s.size() == 3) { ASN1TaggedObject tagged1 = ASN1TaggedObject.getInstance(s.getObjectAt(0)); ASN1TaggedObject tagged2 = ASN1TaggedObject.getInstance(s.getObjectAt(1)); this.currentSpec = new IESParameterSpec(ASN1OctetString.getInstance(tagged1, false).getOctets(), ASN1OctetString.getInstance(tagged2, false).getOctets(), ASN1Integer.getInstance(s.getObjectAt(2)).getValue().intValue()); } + else if (s.size() == 4) + { + ASN1TaggedObject tagged1 = ASN1TaggedObject.getInstance(s.getObjectAt(0)); + ASN1TaggedObject tagged2 = ASN1TaggedObject.getInstance(s.getObjectAt(1)); + ASN1Sequence cipherDet = ASN1Sequence.getInstance(s.getObjectAt(3)); + + this.currentSpec = new IESParameterSpec(ASN1OctetString.getInstance(tagged1, false).getOctets(), ASN1OctetString.getInstance(tagged2, false).getOctets(), ASN1Integer.getInstance(s.getObjectAt(2)).getValue().intValue(), + ASN1Integer.getInstance(cipherDet.getObjectAt(0)).getValue().intValue(), + ASN1OctetString.getInstance(cipherDet.getObjectAt(1)).getOctets()); + } } catch (ClassCastException e) { diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java 2016-03-05 17:24:26.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java 2016-12-20 05:05:56.000000000 +0000 @@ -32,6 +32,7 @@ import org.bouncycastle.crypto.engines.RSABlindedEngine; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseCipherSpi; +import org.bouncycastle.jcajce.provider.util.BadBlockException; import org.bouncycastle.jcajce.provider.util.DigestFactory; import org.bouncycastle.jcajce.util.BCJcaJceHelper; import org.bouncycastle.jcajce.util.JcaJceHelper; @@ -478,18 +479,7 @@ } } - try - { - byte[] bytes = bOut.toByteArray(); - - bOut.reset(); - - return cipher.processBlock(bytes, 0, bytes.length); - } - catch (InvalidCipherTextException e) - { - throw new BadPaddingException(e.getMessage()); - } + return getOutput(); } protected int engineDoFinal( @@ -520,29 +510,37 @@ } } - byte[] out; + byte[] out = getOutput(); + + for (int i = 0; i != out.length; i++) + { + output[outputOffset + i] = out[i]; + } + + return out.length; + } + private byte[] getOutput() + throws BadPaddingException + { try { byte[] bytes = bOut.toByteArray(); - out = cipher.processBlock(bytes, 0, bytes.length); + return cipher.processBlock(bytes, 0, bytes.length); } catch (InvalidCipherTextException e) { - throw new BadPaddingException(e.getMessage()); + throw new BadBlockException("unable to decrypt block", e); } - finally + catch (ArrayIndexOutOfBoundsException e) { - bOut.reset(); + throw new BadBlockException("unable to decrypt block", e); } - - for (int i = 0; i != out.length; i++) + finally { - output[outputOffset + i] = out[i]; + bOut.reset(); } - - return out.length; } /** diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java 2016-04-25 04:31:14.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java 2016-12-22 00:30:24.000000000 +0000 @@ -25,20 +25,13 @@ import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.MD2Digest; import org.bouncycastle.crypto.digests.MD4Digest; -import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.crypto.digests.NullDigest; import org.bouncycastle.crypto.digests.RIPEMD128Digest; import org.bouncycastle.crypto.digests.RIPEMD160Digest; import org.bouncycastle.crypto.digests.RIPEMD256Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA3Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; -import org.bouncycastle.crypto.digests.SHA512tDigest; import org.bouncycastle.crypto.encodings.PKCS1Encoding; import org.bouncycastle.crypto.engines.RSABlindedEngine; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.util.Arrays; public class DigestSignatureSpi @@ -256,7 +249,7 @@ { public SHA1() { - super(OIWObjectIdentifiers.idSHA1, new SHA1Digest(), new PKCS1Encoding(new RSABlindedEngine())); + super(OIWObjectIdentifiers.idSHA1, DigestFactory.createSHA1(), new PKCS1Encoding(new RSABlindedEngine())); } } @@ -265,7 +258,7 @@ { public SHA224() { - super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine())); + super(NISTObjectIdentifiers.id_sha224, DigestFactory.createSHA224(), new PKCS1Encoding(new RSABlindedEngine())); } } @@ -274,7 +267,7 @@ { public SHA256() { - super(NISTObjectIdentifiers.id_sha256, new SHA256Digest(), new PKCS1Encoding(new RSABlindedEngine())); + super(NISTObjectIdentifiers.id_sha256, DigestFactory.createSHA256(), new PKCS1Encoding(new RSABlindedEngine())); } } @@ -283,7 +276,7 @@ { public SHA384() { - super(NISTObjectIdentifiers.id_sha384, new SHA384Digest(), new PKCS1Encoding(new RSABlindedEngine())); + super(NISTObjectIdentifiers.id_sha384, DigestFactory.createSHA384(), new PKCS1Encoding(new RSABlindedEngine())); } } @@ -292,7 +285,7 @@ { public SHA512() { - super(NISTObjectIdentifiers.id_sha512, new SHA512Digest(), new PKCS1Encoding(new RSABlindedEngine())); + super(NISTObjectIdentifiers.id_sha512, DigestFactory.createSHA512(), new PKCS1Encoding(new RSABlindedEngine())); } } @@ -301,7 +294,7 @@ { public SHA512_224() { - super(NISTObjectIdentifiers.id_sha512_224, new SHA512tDigest(224), new PKCS1Encoding(new RSABlindedEngine())); + super(NISTObjectIdentifiers.id_sha512_224, DigestFactory.createSHA512_224(), new PKCS1Encoding(new RSABlindedEngine())); } } @@ -310,7 +303,7 @@ { public SHA512_256() { - super(NISTObjectIdentifiers.id_sha512_256, new SHA512tDigest(256), new PKCS1Encoding(new RSABlindedEngine())); + super(NISTObjectIdentifiers.id_sha512_256, DigestFactory.createSHA512_256(), new PKCS1Encoding(new RSABlindedEngine())); } } @@ -319,7 +312,7 @@ { public SHA3_224() { - super(NISTObjectIdentifiers.id_sha3_224, new SHA3Digest(224), new PKCS1Encoding(new RSABlindedEngine())); + super(NISTObjectIdentifiers.id_sha3_224, DigestFactory.createSHA3_224(), new PKCS1Encoding(new RSABlindedEngine())); } } @@ -328,7 +321,7 @@ { public SHA3_256() { - super(NISTObjectIdentifiers.id_sha3_256, new SHA3Digest(256), new PKCS1Encoding(new RSABlindedEngine())); + super(NISTObjectIdentifiers.id_sha3_256, DigestFactory.createSHA3_256(), new PKCS1Encoding(new RSABlindedEngine())); } } @@ -337,7 +330,7 @@ { public SHA3_384() { - super(NISTObjectIdentifiers.id_sha3_384, new SHA3Digest(384), new PKCS1Encoding(new RSABlindedEngine())); + super(NISTObjectIdentifiers.id_sha3_384, DigestFactory.createSHA3_384(), new PKCS1Encoding(new RSABlindedEngine())); } } @@ -346,7 +339,7 @@ { public SHA3_512() { - super(NISTObjectIdentifiers.id_sha3_512, new SHA3Digest(512), new PKCS1Encoding(new RSABlindedEngine())); + super(NISTObjectIdentifiers.id_sha3_512, DigestFactory.createSHA3_512(), new PKCS1Encoding(new RSABlindedEngine())); } } @@ -373,7 +366,7 @@ { public MD5() { - super(PKCSObjectIdentifiers.md5, new MD5Digest(), new PKCS1Encoding(new RSABlindedEngine())); + super(PKCSObjectIdentifiers.md5, DigestFactory.createMD5(), new PKCS1Encoding(new RSABlindedEngine())); } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java 2015-09-05 23:12:36.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java 2016-12-22 02:37:12.000000000 +0000 @@ -12,17 +12,11 @@ import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.crypto.digests.RIPEMD160Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; -import org.bouncycastle.crypto.digests.SHA512tDigest; import org.bouncycastle.crypto.digests.WhirlpoolDigest; import org.bouncycastle.crypto.engines.RSABlindedEngine; import org.bouncycastle.crypto.signers.ISO9796d2Signer; +import org.bouncycastle.crypto.util.DigestFactory; public class ISOSignatureSpi extends SignatureSpi @@ -124,7 +118,7 @@ { public SHA1WithRSAEncryption() { - super(new SHA1Digest(), new RSABlindedEngine()); + super(DigestFactory.createSHA1(), new RSABlindedEngine()); } } @@ -133,7 +127,7 @@ { public MD5WithRSAEncryption() { - super(new MD5Digest(), new RSABlindedEngine()); + super(DigestFactory.createMD5(), new RSABlindedEngine()); } } @@ -151,7 +145,7 @@ { public SHA224WithRSAEncryption() { - super(new SHA224Digest(), new RSABlindedEngine()); + super(DigestFactory.createSHA224(), new RSABlindedEngine()); } } @@ -160,7 +154,7 @@ { public SHA256WithRSAEncryption() { - super(new SHA256Digest(), new RSABlindedEngine()); + super(DigestFactory.createSHA256(), new RSABlindedEngine()); } } @@ -169,7 +163,7 @@ { public SHA384WithRSAEncryption() { - super(new SHA384Digest(), new RSABlindedEngine()); + super(DigestFactory.createSHA384(), new RSABlindedEngine()); } } @@ -178,7 +172,7 @@ { public SHA512WithRSAEncryption() { - super(new SHA512Digest(), new RSABlindedEngine()); + super(DigestFactory.createSHA512(), new RSABlindedEngine()); } } @@ -187,7 +181,7 @@ { public SHA512_224WithRSAEncryption() { - super(new SHA512tDigest(224), new RSABlindedEngine()); + super(DigestFactory.createSHA512_224(), new RSABlindedEngine()); } } @@ -196,7 +190,7 @@ { public SHA512_256WithRSAEncryption() { - super(new SHA512tDigest(256), new RSABlindedEngine()); + super(DigestFactory.createSHA512_256(), new RSABlindedEngine()); } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/X931SignatureSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/X931SignatureSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/X931SignatureSpi.java 2015-09-05 22:46:48.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/X931SignatureSpi.java 2016-12-22 02:07:48.000000000 +0000 @@ -14,15 +14,10 @@ import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.RIPEMD128Digest; import org.bouncycastle.crypto.digests.RIPEMD160Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; -import org.bouncycastle.crypto.digests.SHA512tDigest; import org.bouncycastle.crypto.digests.WhirlpoolDigest; import org.bouncycastle.crypto.engines.RSABlindedEngine; import org.bouncycastle.crypto.signers.X931Signer; +import org.bouncycastle.crypto.util.DigestFactory; public class X931SignatureSpi extends SignatureSpi @@ -142,7 +137,7 @@ { public SHA1WithRSAEncryption() { - super(new SHA1Digest(), new RSABlindedEngine()); + super(DigestFactory.createSHA1(), new RSABlindedEngine()); } } @@ -151,7 +146,7 @@ { public SHA224WithRSAEncryption() { - super(new SHA224Digest(), new RSABlindedEngine()); + super(DigestFactory.createSHA224(), new RSABlindedEngine()); } } @@ -160,7 +155,7 @@ { public SHA256WithRSAEncryption() { - super(new SHA256Digest(), new RSABlindedEngine()); + super(DigestFactory.createSHA256(), new RSABlindedEngine()); } } @@ -169,7 +164,7 @@ { public SHA384WithRSAEncryption() { - super(new SHA384Digest(), new RSABlindedEngine()); + super(DigestFactory.createSHA384(), new RSABlindedEngine()); } } @@ -178,7 +173,7 @@ { public SHA512WithRSAEncryption() { - super(new SHA512Digest(), new RSABlindedEngine()); + super(DigestFactory.createSHA512(), new RSABlindedEngine()); } } @@ -187,7 +182,7 @@ { public SHA512_224WithRSAEncryption() { - super(new SHA512tDigest(224), new RSABlindedEngine()); + super(DigestFactory.createSHA512_224(), new RSABlindedEngine()); } } @@ -196,7 +191,7 @@ { public SHA512_256WithRSAEncryption() { - super(new SHA512tDigest(256), new RSABlindedEngine()); + super(DigestFactory.createSHA512_256(), new RSABlindedEngine()); } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java 2016-04-25 05:03:31.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java 2016-10-20 23:35:47.000000000 +0000 @@ -39,6 +39,11 @@ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS"); + provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-224WITHRSAANDMGF1", "PSS"); + provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-256WITHRSAANDMGF1", "PSS"); + provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-384WITHRSAANDMGF1", "PSS"); + provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-512WITHRSAANDMGF1", "PSS"); + provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RAWRSAPSS", "PSS"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAPSS", "PSS"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSASSA-PSS", "PSS"); @@ -138,8 +143,8 @@ addDigestSignature(provider, "SHA256", PREFIX + "DigestSignatureSpi$SHA256", PKCSObjectIdentifiers.sha256WithRSAEncryption); addDigestSignature(provider, "SHA384", PREFIX + "DigestSignatureSpi$SHA384", PKCSObjectIdentifiers.sha384WithRSAEncryption); addDigestSignature(provider, "SHA512", PREFIX + "DigestSignatureSpi$SHA512", PKCSObjectIdentifiers.sha512WithRSAEncryption); - addDigestSignature(provider, "SHA512(224)", PREFIX + "DigestSignatureSpi$SHA512_224", null); - addDigestSignature(provider, "SHA512(256)", PREFIX + "DigestSignatureSpi$SHA512_256", null); + addDigestSignature(provider, "SHA512(224)", PREFIX + "DigestSignatureSpi$SHA512_224", PKCSObjectIdentifiers.sha512_224WithRSAEncryption); + addDigestSignature(provider, "SHA512(256)", PREFIX + "DigestSignatureSpi$SHA512_256", PKCSObjectIdentifiers.sha512_256WithRSAEncryption); addDigestSignature(provider, "SHA3-224", PREFIX + "DigestSignatureSpi$SHA3_224", NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_224); addDigestSignature(provider, "SHA3-256", PREFIX + "DigestSignatureSpi$SHA3_256", NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_256); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java 2016-02-25 06:21:21.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java 2016-09-12 09:43:14.000000000 +0000 @@ -176,7 +176,7 @@ { if (algDetails.indexOf('[') > 0) { - return (Integer.parseInt(algDetails.substring(algDetails.indexOf('[') + 1, algDetails.indexOf(']'))) + 7) / 8; + return Integer.parseInt(algDetails.substring(algDetails.indexOf('[') + 1, algDetails.indexOf(']'))); } String algKey = Strings.toUpperCase(algDetails); @@ -300,12 +300,14 @@ } } - if (des.containsKey(oidAlgorithm)) + String algName = getAlgorithm(algorithm); + + if (des.containsKey(algName)) { DESParameters.setOddParity(secret); } - return new SecretKeySpec(secret, getAlgorithm(algorithm)); + return new SecretKeySpec(secret, algName); } protected abstract byte[] calcSecret(); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java 2015-02-14 03:20:28.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java 2016-08-23 00:53:22.000000000 +0000 @@ -152,9 +152,15 @@ { throw new InvalidKeyException(e.getMessage()); } - catch (BadPaddingException e) + catch (final BadPaddingException e) { - throw new InvalidKeyException(e.getMessage()); + throw new InvalidKeyException("unable to unwrap") + { + public synchronized Throwable getCause() + { + return e; + } + }; } catch (IllegalBlockSizeException e2) { diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java 2015-04-03 00:10:03.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java 2016-10-18 03:48:43.000000000 +0000 @@ -28,12 +28,12 @@ } catch (Exception e) { - throw new InvalidKeySpecException("encoded key spec not recognised"); + throw new InvalidKeySpecException("encoded key spec not recognized: " + e.getMessage()); } } else { - throw new InvalidKeySpecException("key spec not recognised"); + throw new InvalidKeySpecException("key spec not recognized"); } } @@ -49,12 +49,12 @@ } catch (Exception e) { - throw new InvalidKeySpecException("encoded key spec not recognised"); + throw new InvalidKeySpecException("encoded key spec not recognized: " + e.getMessage()); } } else { - throw new InvalidKeySpecException("key spec not recognised"); + throw new InvalidKeySpecException("key spec not recognized"); } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java 2013-02-17 03:39:39.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java 2016-10-29 23:14:45.000000000 +0000 @@ -11,6 +11,7 @@ import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.crypto.params.DHPrivateKeyParameters; import org.bouncycastle.crypto.params.DHPublicKeyParameters; +import org.bouncycastle.jcajce.provider.asymmetric.dh.BCDHPublicKey; /** * utility class for converting jce/jca DH objects @@ -22,6 +23,10 @@ PublicKey key) throws InvalidKeyException { + if (key instanceof BCDHPublicKey) + { + return ((BCDHPublicKey)key).engineGetKeyParameters(); + } if (key instanceof DHPublicKey) { DHPublicKey k = (DHPublicKey)key; diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java 2015-06-28 02:29:40.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java 2016-10-18 06:01:11.000000000 +0000 @@ -10,13 +10,16 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Map; +import java.util.Set; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.ec.CustomNamedCurves; +import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import org.bouncycastle.jce.spec.ECNamedCurveSpec; import org.bouncycastle.math.ec.ECAlgorithms; @@ -43,6 +46,13 @@ customCurves.put(curveParams.getCurve(), CustomNamedCurves.getByName(name).getCurve()); } } + + X9ECParameters c25519 = CustomNamedCurves.getByName("Curve25519"); + + customCurves.put(new ECCurve.Fp( + c25519.getCurve().getField().getCharacteristic(), + c25519.getCurve().getA().toBigInteger(), + c25519.getCurve().getB().toBigInteger()), c25519.getCurve()); } public static ECCurve getCurve( @@ -50,28 +60,66 @@ X962Parameters params) { ECCurve curve; + Set acceptableCurves = configuration.getAcceptableNamedCurves(); if (params.isNamedCurve()) { ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); - X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid); - curve = ecP.getCurve(); + if (acceptableCurves.isEmpty() || acceptableCurves.contains(oid)) + { + X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid); + + if (ecP == null) + { + ecP = (X9ECParameters)configuration.getAdditionalECParameters().get(oid); + } + + curve = ecP.getCurve(); + } + else + { + throw new IllegalStateException("named curve not acceptable"); + } } else if (params.isImplicitlyCA()) { curve = configuration.getEcImplicitlyCa().getCurve(); } - else + else if (acceptableCurves.isEmpty()) { X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); curve = ecP.getCurve(); } + else + { + throw new IllegalStateException("encoded parameters not acceptable"); + } return curve; } + public static ECDomainParameters getDomainParameters( + ProviderConfiguration configuration, + java.security.spec.ECParameterSpec params) + { + ECDomainParameters domainParameters; + + if (params == null) + { + org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa(); + + domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed()); + } + else + { + domainParameters = ECUtil.getDomainParameters(configuration, convertSpec(params, false)); + } + + return domainParameters; + } + public static ECParameterSpec convertToSpec( X962Parameters params, ECCurve curve) { @@ -82,6 +130,14 @@ { ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters(); X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid); + if (ecP == null) + { + Map additionalECParameters = BouncyCastleProvider.CONFIGURATION.getAdditionalECParameters(); + if (!additionalECParameters.isEmpty()) + { + ecP = (X9ECParameters)additionalECParameters.get(oid); + } + } ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed()); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java 2015-11-27 21:03:22.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java 2016-10-18 03:48:03.000000000 +0000 @@ -5,6 +5,7 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.util.Enumeration; +import java.util.Map; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.anssi.ANSSINamedCurves; @@ -16,16 +17,19 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X962NamedCurves; +import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.ec.CustomNamedCurves; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECNamedDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; -import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; +import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import org.bouncycastle.jce.interfaces.ECPrivateKey; import org.bouncycastle.jce.interfaces.ECPublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import org.bouncycastle.jce.spec.ECParameterSpec; /** @@ -104,6 +108,67 @@ return res; } + public static ECDomainParameters getDomainParameters( + ProviderConfiguration configuration, + org.bouncycastle.jce.spec.ECParameterSpec params) + { + ECDomainParameters domainParameters; + + if (params instanceof ECNamedCurveParameterSpec) + { + ECNamedCurveParameterSpec nParams = (ECNamedCurveParameterSpec)params; + ASN1ObjectIdentifier nameOid = ECUtil.getNamedCurveOid(nParams.getName()); + + domainParameters = new ECNamedDomainParameters(nameOid, nParams.getCurve(), nParams.getG(), nParams.getN(), nParams.getH(), nParams.getSeed()); + } + else if (params == null) + { + org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa(); + + domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed()); + } + else + { + domainParameters = new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH(), params.getSeed()); + } + + return domainParameters; + } + + public static ECDomainParameters getDomainParameters( + ProviderConfiguration configuration, + X962Parameters params) + { + ECDomainParameters domainParameters; + + if (params.isNamedCurve()) + { + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); + X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid); + if (ecP == null) + { + Map extraCurves = configuration.getAdditionalECParameters(); + + ecP = (X9ECParameters)extraCurves.get(oid); + } + domainParameters = new ECNamedDomainParameters(oid, ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); + } + else if (params.isImplicitlyCA()) + { + org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa(); + + domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed()); + } + else + { + X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); + + domainParameters = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); + } + + return domainParameters; + } + public static AsymmetricKeyParameter generatePublicKeyParameter( PublicKey key) throws InvalidKeyException @@ -113,20 +178,9 @@ ECPublicKey k = (ECPublicKey)key; ECParameterSpec s = k.getParameters(); - if (s == null) - { - s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - - return new ECPublicKeyParameters( - ((BCECPublicKey)k).engineGetQ(), - new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); - } - else - { - return new ECPublicKeyParameters( + return new ECPublicKeyParameters( k.getQ(), new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); - } } else if (key instanceof java.security.interfaces.ECPublicKey) { @@ -218,11 +272,11 @@ throw new InvalidKeyException("can't identify EC private key."); } - public static int getOrderBitLength(BigInteger order, BigInteger privateValue) + public static int getOrderBitLength(ProviderConfiguration configuration, BigInteger order, BigInteger privateValue) { if (order == null) // implicitly CA { - ECParameterSpec implicitCA = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + ECParameterSpec implicitCA = configuration.getEcImplicitlyCa(); if (implicitCA == null) { diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/IESUtil.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/IESUtil.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/IESUtil.java 2015-07-19 04:18:55.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/IESUtil.java 2016-08-27 00:19:46.000000000 +0000 @@ -6,7 +6,7 @@ public class IESUtil { - public static IESParameterSpec guessParameterSpec(BufferedBlockCipher iesBlockCipher) + public static IESParameterSpec guessParameterSpec(BufferedBlockCipher iesBlockCipher, byte[] nonce) { if (iesBlockCipher == null) { @@ -21,18 +21,18 @@ underlyingCipher.getAlgorithmName().equals("RC5-32") || underlyingCipher.getAlgorithmName().equals("RC5-64")) { - return new IESParameterSpec(null, null, 64, 64); + return new IESParameterSpec(null, null, 64, 64, nonce); } else if (underlyingCipher.getAlgorithmName().equals("SKIPJACK")) { - return new IESParameterSpec(null, null, 80, 80); + return new IESParameterSpec(null, null, 80, 80, nonce); } else if (underlyingCipher.getAlgorithmName().equals("GOST28147")) { - return new IESParameterSpec(null, null, 256, 256); + return new IESParameterSpec(null, null, 256, 256, nonce); } - return new IESParameterSpec(null, null, 128, 128); + return new IESParameterSpec(null, null, 128, 128, nonce); } } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java 2016-02-09 23:43:22.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java 2016-10-20 23:45:51.000000000 +0000 @@ -16,20 +16,17 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.jcajce.util.MessageDigestUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; class X509SignatureUtil { private static final ASN1Null derNull = DERNull.INSTANCE; - + static void setSignatureParameters( Signature signature, ASN1Encodable params) @@ -119,49 +116,14 @@ private static String getDigestAlgName( ASN1ObjectIdentifier digestAlgOID) { - if (PKCSObjectIdentifiers.md5.equals(digestAlgOID)) - { - return "MD5"; - } - else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID)) - { - return "SHA1"; - } - else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID)) - { - return "SHA224"; - } - else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID)) - { - return "SHA256"; - } - else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID)) - { - return "SHA384"; - } - else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID)) - { - return "SHA512"; - } - else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID)) - { - return "RIPEMD128"; - } - else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID)) - { - return "RIPEMD160"; - } - else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID)) - { - return "RIPEMD256"; - } - else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID)) - { - return "GOST3411"; - } - else + String name = MessageDigestUtils.getDigestName(digestAlgOID); + + int dIndex = name.indexOf('-'); + if (dIndex > 0 && !name.startsWith("SHA3")) { - return digestAlgOID.getId(); + return name.substring(0, dIndex) + name.substring(dIndex + 1); } + + return MessageDigestUtils.getDigestName(digestAlgOID); } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java 2015-07-02 12:22:20.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java 2016-10-18 03:33:42.000000000 +0000 @@ -29,6 +29,16 @@ */ static final String DH_DEFAULT_PARAMS = "DhDefaultParams"; + /** + * A set of OBJECT IDENTIFIERs representing acceptable named curves for imported keys. + */ + static final String ACCEPTABLE_EC_CURVES = "acceptableEcCurves"; + + /** + * A set of OBJECT IDENTIFIERs to EC Curves providing local curve name mapping. + */ + static final String ADDITIONAL_EC_PARAMETERS = "additionalEcParameters"; + void setParameter(String parameterName, Object parameter); void addAlgorithm(String key, String value); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java 2013-04-08 06:25:01.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java 2016-10-18 03:31:16.000000000 +0000 @@ -1,5 +1,8 @@ package org.bouncycastle.jcajce.provider.config; +import java.util.Map; +import java.util.Set; + import javax.crypto.spec.DHParameterSpec; import org.bouncycastle.jce.spec.ECParameterSpec; @@ -9,4 +12,8 @@ ECParameterSpec getEcImplicitlyCa(); DHParameterSpec getDHDefaultParameters(int keySize); + + Set getAcceptableNamedCurves(); + + Map getAdditionalECParameters(); } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java 2013-02-17 03:40:12.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java 2016-10-18 03:33:42.000000000 +0000 @@ -27,18 +27,23 @@ public class ProviderConfigurationPermission extends BasicPermission { - private static final int THREAD_LOCAL_EC_IMPLICITLY_CA = 0x01; - private static final int EC_IMPLICITLY_CA = 0x02; - private static final int THREAD_LOCAL_DH_DEFAULT_PARAMS = 0x04; - private static final int DH_DEFAULT_PARAMS = 0x08; - - private static final int ALL = THREAD_LOCAL_EC_IMPLICITLY_CA | EC_IMPLICITLY_CA | THREAD_LOCAL_DH_DEFAULT_PARAMS | DH_DEFAULT_PARAMS; + private static final int THREAD_LOCAL_EC_IMPLICITLY_CA = 0x01; + private static final int EC_IMPLICITLY_CA = 0x02; + private static final int THREAD_LOCAL_DH_DEFAULT_PARAMS = 0x04; + private static final int DH_DEFAULT_PARAMS = 0x08; + private static final int ACCEPTABLE_EC_CURVES = 0x10; + private static final int ADDITIONAL_EC_PARAMETERS = 0x20; + + private static final int ALL = + THREAD_LOCAL_EC_IMPLICITLY_CA | EC_IMPLICITLY_CA | THREAD_LOCAL_DH_DEFAULT_PARAMS | DH_DEFAULT_PARAMS | + ACCEPTABLE_EC_CURVES | ADDITIONAL_EC_PARAMETERS; private static final String THREAD_LOCAL_EC_IMPLICITLY_CA_STR = "threadlocalecimplicitlyca"; private static final String EC_IMPLICITLY_CA_STR = "ecimplicitlyca"; private static final String THREAD_LOCAL_DH_DEFAULT_PARAMS_STR = "threadlocaldhdefaultparams"; private static final String DH_DEFAULT_PARAMS_STR = "dhdefaultparams"; - + private static final String ACCEPTABLE_EC_CURVES_STR = "acceptableeccurves"; + private static final String ADDITIONAL_EC_PARAMETERS_STR = "additionalecparameters"; private static final String ALL_STR = "all"; private final String actions; @@ -84,6 +89,14 @@ { mask |= DH_DEFAULT_PARAMS; } + else if (s.equals(ACCEPTABLE_EC_CURVES_STR)) + { + mask |= ACCEPTABLE_EC_CURVES; + } + else if (s.equals(ADDITIONAL_EC_PARAMETERS_STR)) + { + mask |= ADDITIONAL_EC_PARAMETERS; + } else if (s.equals(ALL_STR)) { mask |= ALL; diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java 2013-03-04 03:32:46.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java 2016-10-05 23:49:47.000000000 +0000 @@ -68,6 +68,8 @@ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA224", "SHA-224"); provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha224, "SHA-224"); + provider.addAlgorithm("Mac.PBEWITHHMACSHA224", PREFIX + "$HashMac"); + addHMACAlgorithm(provider, "SHA224", PREFIX + "$HashMac", PREFIX + "$KeyGenerator"); addHMACAlias(provider, "SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java 2016-01-15 17:46:50.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java 2016-10-05 23:50:57.000000000 +0000 @@ -88,6 +88,8 @@ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHHMACSHA-256", "PBEWITHHMACSHA256"); provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + NISTObjectIdentifiers.id_sha256, "PBEWITHHMACSHA256"); + provider.addAlgorithm("Mac.PBEWITHHMACSHA256", PREFIX + "$HashMac"); + addHMACAlgorithm(provider, "SHA256", PREFIX + "$HashMac", PREFIX + "$KeyGenerator"); addHMACAlias(provider, "SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256); addHMACAlias(provider, "SHA256", NISTObjectIdentifiers.id_sha256); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java 2013-03-04 03:32:46.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java 2016-10-05 23:50:57.000000000 +0000 @@ -82,6 +82,8 @@ provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha384, "SHA-384"); provider.addAlgorithm("Mac.OLDHMACSHA384", PREFIX + "$OldSHA384"); + provider.addAlgorithm("Mac.PBEWITHHMACSHA384", PREFIX + "$HashMac"); + addHMACAlgorithm(provider, "SHA384", PREFIX + "$HashMac", PREFIX + "$KeyGenerator"); addHMACAlias(provider, "SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384); } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java 2013-03-04 03:32:46.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java 2016-10-05 23:50:57.000000000 +0000 @@ -168,6 +168,8 @@ provider.addAlgorithm("Mac.OLDHMACSHA512", PREFIX + "$OldSHA512"); + provider.addAlgorithm("Mac.PBEWITHHMACSHA512", PREFIX + "$HashMac"); + addHMACAlgorithm(provider, "SHA512", PREFIX + "$HashMac", PREFIX + "$KeyGenerator"); addHMACAlias(provider, "SHA512", PKCSObjectIdentifiers.id_hmacWithSHA512); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java 2016-12-19 23:38:40.000000000 +0000 @@ -0,0 +1,199 @@ +package org.bouncycastle.jcajce.provider.drbg; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.SecureRandomSpi; + +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.prng.EntropySource; +import org.bouncycastle.crypto.prng.EntropySourceProvider; +import org.bouncycastle.crypto.prng.SP800SecureRandomBuilder; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; +import org.bouncycastle.util.Strings; + +public class DRBG +{ + private static final String PREFIX = DRBG.class.getName(); + + // {"Provider class name","SecureRandomSpi class name"} + private static final String[][] initialEntropySourceNames = new String[][] + { + // Normal JVM + {"sun.security.provider.Sun", "sun.security.provider.SecureRandom"}, + // Apache harmony + {"org.apache.harmony.security.provider.crypto.CryptoProvider", "org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl"}, + // Android. + {"com.android.org.conscrypt.OpenSSLProvider", "com.android.org.conscrypt.OpenSSLRandom"}, + {"org.conscrypt.OpenSSLProvider", "org.conscrypt.OpenSSLRandom"}, + }; + + private static final Object[] initialEntropySourceAndSpi = findSource(); + + // Cascade through providers looking for match. + private final static Object[] findSource() + { + for (int t = 0; t < initialEntropySourceNames.length; t++) + { + String[] pair = initialEntropySourceNames[t]; + try + { + Object[] r = new Object[]{Class.forName(pair[0]).newInstance(), Class.forName(pair[1]).newInstance()}; + + return r; + } + catch (Throwable ex) + { + continue; + } + } + + return null; + } + + private static class CoreSecureRandom + extends SecureRandom + { + CoreSecureRandom() + { + super((SecureRandomSpi)initialEntropySourceAndSpi[1], (Provider)initialEntropySourceAndSpi[0]); + } + } + + // unfortunately new SecureRandom() can cause a regress and it's the only reliable way of getting access + // to the JVM's seed generator. + private static SecureRandom createInitialEntropySource() + { + if (initialEntropySourceAndSpi != null) + { + return new CoreSecureRandom(); + } + else + { + return new SecureRandom(); // we're desperate, it's worth a try. + } + } + + private static EntropySourceProvider createEntropySource() + { + final String sourceClass = System.getProperty("org.bouncycastle.drbg.entropysource"); + + return AccessController.doPrivileged(new PrivilegedAction() + { + public EntropySourceProvider run() + { + try + { + Class clazz = DRBG.class.getClassLoader().loadClass(sourceClass); + + return (EntropySourceProvider)clazz.newInstance(); + } + catch (Exception e) + { + throw new IllegalStateException("entropy source " + sourceClass + " not created: " + e.getMessage(), e); + } + } + }); + } + + private static SecureRandom createBaseRandom(boolean isPredictionResistant) + { + if (System.getProperty("org.bouncycastle.drbg.entropysource") != null) + { + EntropySourceProvider entropyProvider = createEntropySource(); + + EntropySource initSource = entropyProvider.get(16 * 8); + + return new SP800SecureRandomBuilder(entropyProvider) + .setPersonalizationString(generateDefaultPersonalizationString(initSource.getEntropy())) + .buildHash(new SHA512Digest(), Arrays.concatenate(initSource.getEntropy(), initSource.getEntropy()), isPredictionResistant); + } + else + { + SecureRandom randomSource = createInitialEntropySource(); // needs to be done late, can't use static + return new SP800SecureRandomBuilder(randomSource, true) + .setPersonalizationString(generateDefaultPersonalizationString(randomSource.generateSeed(16))) + .buildHash(new SHA512Digest(), randomSource.generateSeed(32), isPredictionResistant); + } + } + + public static class Default + extends SecureRandomSpi + { + private static final SecureRandom random = createBaseRandom(true); + + public Default() + { + } + + protected void engineSetSeed(byte[] bytes) + { + random.setSeed(bytes); + } + + protected void engineNextBytes(byte[] bytes) + { + random.nextBytes(bytes); + } + + protected byte[] engineGenerateSeed(int numBytes) + { + return random.generateSeed(numBytes); + } + } + + public static class NonceAndIV + extends SecureRandomSpi + { + private static final SecureRandom random = createBaseRandom(false); + + public NonceAndIV() + { + } + + protected void engineSetSeed(byte[] bytes) + { + random.setSeed(bytes); + } + + protected void engineNextBytes(byte[] bytes) + { + random.nextBytes(bytes); + } + + protected byte[] engineGenerateSeed(int numBytes) + { + return random.generateSeed(numBytes); + } + } + + public static class Mappings + extends AsymmetricAlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("SecureRandom.DEFAULT", PREFIX + "$Default"); + provider.addAlgorithm("SecureRandom.NONCEANDIV", PREFIX + "$NonceAndIV"); + } + } + + private static byte[] generateDefaultPersonalizationString(byte[] seed) + { + return Arrays.concatenate(Strings.toByteArray("Default"), seed, + Pack.longToBigEndian(Thread.currentThread().getId()), Pack.longToBigEndian(System.currentTimeMillis())); + } + + private static byte[] generateNonceIVPersonalizationString(byte[] seed) + { + return Arrays.concatenate(Strings.toByteArray("Nonce"), seed, + Pack.longToLittleEndian(Thread.currentThread().getId()), Pack.longToLittleEndian(System.currentTimeMillis())); + } +} diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java 2016-12-19 21:32:09.000000000 +0000 @@ -0,0 +1,973 @@ +package org.bouncycastle.jcajce.provider.keystore.bcfks; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyStoreException; +import java.security.KeyStoreSpi; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.PKCS8EncodedKeySpec; +import java.text.ParseException; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.bc.EncryptedObjectStoreData; +import org.bouncycastle.asn1.bc.EncryptedPrivateKeyData; +import org.bouncycastle.asn1.bc.EncryptedSecretKeyData; +import org.bouncycastle.asn1.bc.ObjectData; +import org.bouncycastle.asn1.bc.ObjectDataSequence; +import org.bouncycastle.asn1.bc.ObjectStore; +import org.bouncycastle.asn1.bc.ObjectStoreData; +import org.bouncycastle.asn1.bc.ObjectStoreIntegrityCheck; +import org.bouncycastle.asn1.bc.PbkdMacIntegrityCheck; +import org.bouncycastle.asn1.bc.SecretKeyData; +import org.bouncycastle.asn1.cms.CCMParameters; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import org.bouncycastle.asn1.pkcs.EncryptionScheme; +import org.bouncycastle.asn1.pkcs.KeyDerivationFunc; +import org.bouncycastle.asn1.pkcs.PBES2Parameters; +import org.bouncycastle.asn1.pkcs.PBKDF2Params; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.crypto.PBEParametersGenerator; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +class BcFKSKeyStoreSpi + extends KeyStoreSpi +{ + private static final Map oidMap = new HashMap(); + private static final Map publicAlgMap = new HashMap(); + + static + { + // Note: AES handled inline + oidMap.put("DESEDE", OIWObjectIdentifiers.desEDE); + oidMap.put("TRIPLEDES", OIWObjectIdentifiers.desEDE); + oidMap.put("TDEA", OIWObjectIdentifiers.desEDE); + oidMap.put("HMACSHA1", PKCSObjectIdentifiers.id_hmacWithSHA1); + oidMap.put("HMACSHA224", PKCSObjectIdentifiers.id_hmacWithSHA224); + oidMap.put("HMACSHA256", PKCSObjectIdentifiers.id_hmacWithSHA256); + oidMap.put("HMACSHA384", PKCSObjectIdentifiers.id_hmacWithSHA384); + oidMap.put("HMACSHA512", PKCSObjectIdentifiers.id_hmacWithSHA512); + + publicAlgMap.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); + publicAlgMap.put(X9ObjectIdentifiers.id_ecPublicKey, "EC"); + publicAlgMap.put(OIWObjectIdentifiers.elGamalAlgorithm, "DH"); + publicAlgMap.put(PKCSObjectIdentifiers.dhKeyAgreement, "DH"); + publicAlgMap.put(X9ObjectIdentifiers.id_dsa, "DSA"); + } + + private static String getPublicKeyAlg(ASN1ObjectIdentifier oid) + { + String algName = (String)publicAlgMap.get(oid); + + if (algName != null) + { + return algName; + } + + return oid.getId(); + } + + private final static BigInteger CERTIFICATE = BigInteger.valueOf(0); + private final static BigInteger PRIVATE_KEY = BigInteger.valueOf(1); + private final static BigInteger SECRET_KEY = BigInteger.valueOf(2); + private final static BigInteger PROTECTED_PRIVATE_KEY = BigInteger.valueOf(3); + private final static BigInteger PROTECTED_SECRET_KEY = BigInteger.valueOf(4); + + private final BouncyCastleProvider provider; + private final Map entries = new HashMap(); + private final Map privateKeyCache = new HashMap(); + + private AlgorithmIdentifier hmacAlgorithm; + private KeyDerivationFunc hmacPkbdAlgorithm; + private Date creationDate; + private Date lastModifiedDate; + + BcFKSKeyStoreSpi(BouncyCastleProvider provider) + { + this.provider = provider; + } + + public Key engineGetKey(String alias, char[] password) + throws NoSuchAlgorithmException, UnrecoverableKeyException + { + ObjectData ent = (ObjectData)entries.get(alias); + + if (ent != null) + { + if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY)) + { + PrivateKey cachedKey = (PrivateKey)privateKeyCache.get(alias); + if (cachedKey != null) + { + return cachedKey; + } + + EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData()); + EncryptedPrivateKeyInfo encInfo = EncryptedPrivateKeyInfo.getInstance(encPrivData.getEncryptedPrivateKeyInfo()); + + try + { + PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(decryptData("PRIVATE_KEY_ENCRYPTION", encInfo.getEncryptionAlgorithm(), password, encInfo.getEncryptedData())); + + KeyFactory kFact; + if (provider != null) + { + kFact = KeyFactory.getInstance(pInfo.getPrivateKeyAlgorithm().getAlgorithm().getId(), provider); + } + else + { + kFact = KeyFactory.getInstance(getPublicKeyAlg(pInfo.getPrivateKeyAlgorithm().getAlgorithm())); + } + + PrivateKey privateKey = kFact.generatePrivate(new PKCS8EncodedKeySpec(pInfo.getEncoded())); + + // check that the key pair and the certificate public key are consistent + // TODO: new ConsistentKeyPair(engineGetCertificate(alias).getPublicKey(), privateKey); + + privateKeyCache.put(alias, privateKey); + + return privateKey; + } + catch (Exception e) + { + throw new UnrecoverableKeyException("BCFKS KeyStore unable to recover private key (" + alias + "): " + e.getMessage()); + } + } + else if (ent.getType().equals(SECRET_KEY) || ent.getType().equals(PROTECTED_SECRET_KEY)) + { + EncryptedSecretKeyData encKeyData = EncryptedSecretKeyData.getInstance(ent.getData()); + + try + { + SecretKeyData keyData = SecretKeyData.getInstance(decryptData("SECRET_KEY_ENCRYPTION", encKeyData.getKeyEncryptionAlgorithm(), password, encKeyData.getEncryptedKeyData())); + SecretKeyFactory kFact; + if (provider != null) + { + kFact = SecretKeyFactory.getInstance(keyData.getKeyAlgorithm().getId(), provider); + } + else + { + kFact = SecretKeyFactory.getInstance(keyData.getKeyAlgorithm().getId()); + } + + return kFact.generateSecret(new SecretKeySpec(keyData.getKeyBytes(), keyData.getKeyAlgorithm().getId())); + } + catch (Exception e) + { + throw new UnrecoverableKeyException("BCFKS KeyStore unable to recover secret key (" + alias + "): " + e.getMessage()); + } + } + else + { + throw new UnrecoverableKeyException("BCFKS KeyStore unable to recover secret key (" + alias + "): type not recognized"); + } + } + + return null; + } + + public Certificate[] engineGetCertificateChain(String alias) + { + ObjectData ent = (ObjectData)entries.get(alias); + + if (ent != null) + { + if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY)) + { + EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData()); + org.bouncycastle.asn1.x509.Certificate[] certificates = encPrivData.getCertificateChain(); + Certificate[] chain = new X509Certificate[certificates.length]; + + for (int i = 0; i != chain.length; i++) + { + chain[i] = decodeCertificate(certificates[i]); + } + + return chain; + } + } + + return null; + } + + public Certificate engineGetCertificate(String s) + { + ObjectData ent = (ObjectData)entries.get(s); + + if (ent != null) + { + if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY)) + { + EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData()); + org.bouncycastle.asn1.x509.Certificate[] certificates = encPrivData.getCertificateChain(); + + return decodeCertificate(certificates[0]); + } + else if (ent.getType().equals(CERTIFICATE)) + { + return decodeCertificate(ent.getData()); + } + } + + return null; + } + + private Certificate decodeCertificate(Object cert) + { + if (provider != null) + { + try + { + CertificateFactory certFact = CertificateFactory.getInstance("X.509", provider); + + return certFact.generateCertificate(new ByteArrayInputStream(org.bouncycastle.asn1.x509.Certificate.getInstance(cert).getEncoded())); + } + catch (Exception e) + { + return null; + } + } + else + { + try + { + CertificateFactory certFact = CertificateFactory.getInstance("X.509"); + + return certFact.generateCertificate(new ByteArrayInputStream(org.bouncycastle.asn1.x509.Certificate.getInstance(cert).getEncoded())); + } + catch (Exception e) + { + return null; + } + } + } + + public Date engineGetCreationDate(String s) + { + ObjectData ent = (ObjectData)entries.get(s); + + if (ent != null) + { + try + { + // we return last modified as it represents date current state of entry was created + return ent.getLastModifiedDate().getDate(); + } + catch (ParseException e) + { + return new Date(); // it's here, but... + } + } + + return null; + } + + public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) + throws KeyStoreException + { + Date creationDate = new Date(); + Date lastEditDate = creationDate; + + ObjectData entry = (ObjectData)entries.get(alias); + if (entry != null) + { + creationDate = extractCreationDate(entry, creationDate); + } + + privateKeyCache.remove(alias); + + if (key instanceof PrivateKey) + { + if (chain == null) + { + throw new KeyStoreException("BCFKS KeyStore requires a certificate chain for private key storage."); + } + + try + { + // check that the key pair and the certificate public are consistent + // TODO: new ConsistentKeyPair(chain[0].getPublicKey(), (PrivateKey)key); + + byte[] encodedKey = key.getEncoded(); + + KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(256 / 8); + byte[] keyBytes = generateKey(pbkdAlgId, "PRIVATE_KEY_ENCRYPTION", ((password != null) ? password : new char[0])); + + Cipher c; + if (provider == null) + { + c = Cipher.getInstance("AES/CCM/NoPadding"); + } + else + { + c = Cipher.getInstance("AES/CCM/NoPadding", provider); + } + + c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES")); + + byte[] encryptedKey = c.doFinal(encodedKey); + + AlgorithmParameters algParams = c.getParameters(); + + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algParams.getEncoded()))); + + EncryptedPrivateKeyInfo keyInfo = new EncryptedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey); + + EncryptedPrivateKeyData keySeq = createPrivateKeySequence(keyInfo, chain); + + entries.put(alias, new ObjectData(PRIVATE_KEY, alias, creationDate, lastEditDate, keySeq.getEncoded(), null)); + } + catch (Exception e) + { + throw new ExtKeyStoreException("BCFKS KeyStore exception storing private key: " + e.toString(), e); + } + } + else if (key instanceof SecretKey) + { + if (chain != null) + { + throw new KeyStoreException("BCFKS KeyStore cannot store certificate chain with secret key."); + } + + try + { + byte[] encodedKey = key.getEncoded(); + + KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(256 / 8); + byte[] keyBytes = generateKey(pbkdAlgId, "SECRET_KEY_ENCRYPTION", ((password != null) ? password : new char[0])); + + Cipher c; + if (provider == null) + { + c = Cipher.getInstance("AES/CCM/NoPadding"); + } + else + { + c = Cipher.getInstance("AES/CCM/NoPadding", provider); + } + + c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES")); + + + String keyAlg = Strings.toUpperCase(key.getAlgorithm()); + byte[] encryptedKey; + + if (keyAlg.indexOf("AES") > -1) + { + encryptedKey = c.doFinal(new SecretKeyData(NISTObjectIdentifiers.aes, encodedKey).getEncoded()); + } + else + { + ASN1ObjectIdentifier algOid = (ASN1ObjectIdentifier)oidMap.get(keyAlg); + if (algOid != null) + { + encryptedKey = c.doFinal(new SecretKeyData(algOid, encodedKey).getEncoded()); + } + else + { + throw new KeyStoreException("BCFKS KeyStore cannot recognize secret key (" + keyAlg + ") for storage."); + } + } + + + AlgorithmParameters algParams = c.getParameters(); + + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algParams.getEncoded()))); + + EncryptedSecretKeyData keyData = new EncryptedSecretKeyData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey); + + entries.put(alias, new ObjectData(SECRET_KEY, alias, creationDate, lastEditDate, keyData.getEncoded(), null)); + } + catch (Exception e) + { + throw new ExtKeyStoreException("BCFKS KeyStore exception storing private key: " + e.toString(), e); + } + } + else + { + throw new KeyStoreException("BCFKS KeyStore unable to recognize key."); + } + + lastModifiedDate = lastEditDate; + } + + private SecureRandom getDefaultSecureRandom() + { + return new SecureRandom(); + } + + private EncryptedPrivateKeyData createPrivateKeySequence(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo, Certificate[] chain) + throws CertificateEncodingException + { + org.bouncycastle.asn1.x509.Certificate[] certChain = new org.bouncycastle.asn1.x509.Certificate[chain.length]; + for (int i = 0; i != chain.length; i++) + { + certChain[i] = org.bouncycastle.asn1.x509.Certificate.getInstance(chain[i].getEncoded()); + } + + return new EncryptedPrivateKeyData(encryptedPrivateKeyInfo, certChain); + } + + public void engineSetKeyEntry(String alias, byte[] keyBytes, Certificate[] chain) + throws KeyStoreException + { + Date creationDate = new Date(); + Date lastEditDate = creationDate; + + ObjectData entry = (ObjectData)entries.get(alias); + if (entry != null) + { + creationDate = extractCreationDate(entry, creationDate); + } + + if (chain != null) + { + EncryptedPrivateKeyInfo encInfo; + + try + { + encInfo = EncryptedPrivateKeyInfo.getInstance(keyBytes); + } + catch (Exception e) + { + throw new ExtKeyStoreException("BCFKS KeyStore private key encoding must be an EncryptedPrivateKeyInfo.", e); + } + + try + { + privateKeyCache.remove(alias); + entries.put(alias, new ObjectData(PROTECTED_PRIVATE_KEY, alias, creationDate, lastEditDate, createPrivateKeySequence(encInfo, chain).getEncoded(), null)); + } + catch (Exception e) + { + throw new ExtKeyStoreException("BCFKS KeyStore exception storing protected private key: " + e.toString(), e); + } + } + else + { + try + { + entries.put(alias, new ObjectData(PROTECTED_SECRET_KEY, alias, creationDate, lastEditDate, keyBytes, null)); + } + catch (Exception e) + { + throw new ExtKeyStoreException("BCFKS KeyStore exception storing protected private key: " + e.toString(), e); + } + } + + lastModifiedDate = lastEditDate; + } + + public void engineSetCertificateEntry(String alias, Certificate certificate) + throws KeyStoreException + { + ObjectData entry = (ObjectData)entries.get(alias); + Date creationDate = new Date(); + Date lastEditDate = creationDate; + + if (entry != null) + { + if (!entry.getType().equals(CERTIFICATE)) + { + throw new KeyStoreException("BCFKS KeyStore already has a key entry with alias " + alias); + } + + creationDate = extractCreationDate(entry, creationDate); + } + + try + { + entries.put(alias, new ObjectData(CERTIFICATE, alias, creationDate, lastEditDate, certificate.getEncoded(), null)); + } + catch (CertificateEncodingException e) + { + throw new ExtKeyStoreException("BCFKS KeyStore unable to handle certificate: " + e.getMessage(), e); + } + + lastModifiedDate = lastEditDate; + } + + private Date extractCreationDate(ObjectData entry, Date creationDate) + { + try + { + creationDate = entry.getCreationDate().getDate(); + } + catch (ParseException e) + { + // this should never happen, if it does we'll leave creation date unmodified and hope for the best. + } + return creationDate; + } + + public void engineDeleteEntry(String alias) + throws KeyStoreException + { + ObjectData entry = (ObjectData)entries.get(alias); + + if (entry == null) + { + return; + } + + privateKeyCache.remove(alias); + entries.remove(alias); + + lastModifiedDate = new Date(); + } + + public Enumeration engineAliases() + { + final Iterator it = new HashSet(entries.keySet()).iterator(); + + return new Enumeration() + { + public boolean hasMoreElements() + { + return it.hasNext(); + } + + public Object nextElement() + { + return it.next(); + } + }; + } + + public boolean engineContainsAlias(String alias) + { + if (alias == null) + { + throw new NullPointerException("alias value is null"); + } + + return entries.containsKey(alias); + } + + public int engineSize() + { + return entries.size(); + } + + public boolean engineIsKeyEntry(String alias) + { + ObjectData ent = (ObjectData)entries.get(alias); + + if (ent != null) + { + BigInteger entryType = ent.getType(); + return entryType.equals(PRIVATE_KEY) || entryType.equals(SECRET_KEY) + || entryType.equals(PROTECTED_PRIVATE_KEY) || entryType.equals(PROTECTED_SECRET_KEY); + } + + return false; + } + + public boolean engineIsCertificateEntry(String alias) + { + ObjectData ent = (ObjectData)entries.get(alias); + + if (ent != null) + { + return ent.getType().equals(CERTIFICATE); + } + + return false; + } + + public String engineGetCertificateAlias(Certificate certificate) + { + if (certificate == null) + { + return null; + } + + byte[] encodedCert; + try + { + encodedCert = certificate.getEncoded(); + } + catch (CertificateEncodingException e) + { + return null; + } + + for (Iterator it = entries.keySet().iterator(); it.hasNext(); ) + { + String alias = (String)it.next(); + ObjectData ent = (ObjectData)entries.get(alias); + + if (ent.getType().equals(CERTIFICATE)) + { + if (Arrays.areEqual(ent.getData(), encodedCert)) + { + return alias; + } + } + else if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY)) + { + try + { + EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData()); + if (Arrays.areEqual(encPrivData.getCertificateChain()[0].toASN1Primitive().getEncoded(), encodedCert)) + { + return alias; + } + } + catch (IOException e) + { + // ignore - this should never happen + } + } + } + + return null; + } + + private byte[] generateKey(KeyDerivationFunc pbkdAlgorithm, String purpose, char[] password) + throws IOException + { + byte[] encPassword = PBEParametersGenerator.PKCS12PasswordToBytes(password); + byte[] differentiator = PBEParametersGenerator.PKCS12PasswordToBytes(purpose.toCharArray()); + + int keySizeInBytes; + PKCS5S2ParametersGenerator pGen = new PKCS5S2ParametersGenerator(new SHA512Digest()); + + if (pbkdAlgorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_PBKDF2)) + { + PBKDF2Params pbkdf2Params = PBKDF2Params.getInstance(pbkdAlgorithm.getParameters()); + + if (pbkdf2Params.getPrf().getAlgorithm().equals(PKCSObjectIdentifiers.id_hmacWithSHA512)) + { + + pGen.init(Arrays.concatenate(encPassword, differentiator), pbkdf2Params.getSalt(), pbkdf2Params.getIterationCount().intValue()); + + keySizeInBytes = pbkdf2Params.getKeyLength().intValue(); + } + else + { + throw new IOException("BCFKS KeyStore: unrecognized MAC PBKD PRF."); + } + } + else + { + throw new IOException("BCFKS KeyStore: unrecognized MAC PBKD."); + } + + return ((KeyParameter)pGen.generateDerivedParameters(keySizeInBytes * 8)).getKey(); + } + + private void verifyMac(byte[] content, PbkdMacIntegrityCheck integrityCheck, char[] password) + throws NoSuchAlgorithmException, IOException + { + byte[] check = calculateMac(content, integrityCheck.getMacAlgorithm(), integrityCheck.getPbkdAlgorithm(), password); + + if (!Arrays.constantTimeAreEqual(check, integrityCheck.getMac())) + { + throw new IOException("BCFKS KeyStore corrupted: MAC calculation failed."); + } + } + + private byte[] calculateMac(byte[] content, AlgorithmIdentifier algorithm, KeyDerivationFunc pbkdAlgorithm, char[] password) + throws NoSuchAlgorithmException, IOException + { + String algorithmId = algorithm.getAlgorithm().getId(); + + Mac mac; + if (provider != null) + { + mac = Mac.getInstance(algorithmId, provider); + } + else + { + mac = Mac.getInstance(algorithmId); + } + + try + { + mac.init(new SecretKeySpec(generateKey(pbkdAlgorithm, "INTEGRITY_CHECK", ((password != null) ? password : new char[0])), algorithmId)); + } + catch (InvalidKeyException e) + { + throw new IOException("Cannot set up MAC calculation: " + e.getMessage()); + } + + return mac.doFinal(content); + } + + public void engineStore(OutputStream outputStream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException + { + ObjectData[] dataArray = (ObjectData[])entries.values().toArray(new ObjectData[entries.size()]); + + KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(256 / 8); + byte[] keyBytes = generateKey(pbkdAlgId, "STORE_ENCRYPTION", ((password != null) ? password : new char[0])); + + ObjectStoreData storeData = new ObjectStoreData(hmacAlgorithm, creationDate, lastModifiedDate, new ObjectDataSequence(dataArray), null); + EncryptedObjectStoreData encStoreData; + + try + { + Cipher c; + if (provider == null) + { + c = Cipher.getInstance("AES/CCM/NoPadding"); + } + else + { + c = Cipher.getInstance("AES/CCM/NoPadding", provider); + } + + c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES")); + + byte[] encOut = c.doFinal(storeData.getEncoded()); + + AlgorithmParameters algorithmParameters = c.getParameters(); + + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algorithmParameters.getEncoded()))); + + encStoreData = new EncryptedObjectStoreData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encOut); + } + catch (NoSuchPaddingException e) + { + throw new NoSuchAlgorithmException(e.toString()); + } + catch (BadPaddingException e) + { + throw new IOException(e.toString()); + } + catch (IllegalBlockSizeException e) + { + throw new IOException(e.toString()); + } + catch (InvalidKeyException e) + { + throw new IOException(e.toString()); + } + + // update the salt + PBKDF2Params pbkdf2Params = PBKDF2Params.getInstance(hmacPkbdAlgorithm.getParameters()); + + byte[] pbkdSalt = new byte[pbkdf2Params.getSalt().length]; + getDefaultSecureRandom().nextBytes(pbkdSalt); + + hmacPkbdAlgorithm = new KeyDerivationFunc(hmacPkbdAlgorithm.getAlgorithm(), new PBKDF2Params(pbkdSalt, pbkdf2Params.getIterationCount().intValue(), pbkdf2Params.getKeyLength().intValue(), pbkdf2Params.getPrf())); + + byte[] mac = calculateMac(encStoreData.getEncoded(), hmacAlgorithm, hmacPkbdAlgorithm, password); + + ObjectStore store = new ObjectStore(encStoreData, new ObjectStoreIntegrityCheck(new PbkdMacIntegrityCheck(hmacAlgorithm, hmacPkbdAlgorithm, mac))); + + outputStream.write(store.getEncoded()); + + outputStream.flush(); + } + + public void engineLoad(InputStream inputStream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException + { + // reset any current values + entries.clear(); + privateKeyCache.clear(); + + lastModifiedDate = creationDate = null; + hmacAlgorithm = null; + + if (inputStream == null) + { + // initialise defaults + lastModifiedDate = creationDate = new Date(); + + hmacAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE); + hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(512 / 8); + + return; + } + + ASN1InputStream aIn = new ASN1InputStream(inputStream); + + ObjectStore store = ObjectStore.getInstance(aIn.readObject()); + + ObjectStoreIntegrityCheck integrityCheck = store.getIntegrityCheck(); + if (integrityCheck.getType() == ObjectStoreIntegrityCheck.PBKD_MAC_CHECK) + { + PbkdMacIntegrityCheck pbkdMacIntegrityCheck = PbkdMacIntegrityCheck.getInstance(integrityCheck.getIntegrityCheck()); + + hmacAlgorithm = pbkdMacIntegrityCheck.getMacAlgorithm(); + hmacPkbdAlgorithm = pbkdMacIntegrityCheck.getPbkdAlgorithm(); + + verifyMac(store.getStoreData().toASN1Primitive().getEncoded(), pbkdMacIntegrityCheck, password); + } + else + { + throw new IOException("BCFKS KeyStore unable to recognize integrity check."); + } + + ASN1Encodable sData = store.getStoreData(); + + ObjectStoreData storeData; + if (sData instanceof EncryptedObjectStoreData) + { + EncryptedObjectStoreData encryptedStoreData = (EncryptedObjectStoreData)sData; + AlgorithmIdentifier protectAlgId = encryptedStoreData.getEncryptionAlgorithm(); + + storeData = ObjectStoreData.getInstance(decryptData("STORE_ENCRYPTION", protectAlgId, password, encryptedStoreData.getEncryptedContent().getOctets())); + } + else + { + storeData = ObjectStoreData.getInstance(sData); + } + + try + { + creationDate = storeData.getCreationDate().getDate(); + lastModifiedDate = storeData.getLastModifiedDate().getDate(); + } + catch (ParseException e) + { + throw new IOException("BCFKS KeyStore unable to parse store data information."); + } + + if (!storeData.getIntegrityAlgorithm().equals(hmacAlgorithm)) + { + throw new IOException("BCFKS KeyStore storeData integrity algorithm does not match store integrity algorithm."); + } + + for (Iterator it = storeData.getObjectDataSequence().iterator(); it.hasNext(); ) + { + ObjectData objData = ObjectData.getInstance(it.next()); + + entries.put(objData.getIdentifier(), objData); + } + } + + private byte[] decryptData(String purpose, AlgorithmIdentifier protectAlgId, char[] password, byte[] encryptedData) + throws IOException + { + if (!protectAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_PBES2)) + { + throw new IOException("BCFKS KeyStore cannot recognize protection algorithm."); + } + + PBES2Parameters pbes2Parameters = PBES2Parameters.getInstance(protectAlgId.getParameters()); + EncryptionScheme algId = pbes2Parameters.getEncryptionScheme(); + + if (!algId.getAlgorithm().equals(NISTObjectIdentifiers.id_aes256_CCM)) + { + throw new IOException("BCFKS KeyStore cannot recognize protection encryption algorithm."); + } + + try + { + CCMParameters ccmParameters = CCMParameters.getInstance(algId.getParameters()); + Cipher c; + AlgorithmParameters algParams; + if (provider == null) + { + c = Cipher.getInstance("AES/CCM/NoPadding"); + algParams = AlgorithmParameters.getInstance("CCM"); + } + else + { + c = Cipher.getInstance("AES/CCM/NoPadding", provider); + algParams = AlgorithmParameters.getInstance("CCM", provider); + } + + algParams.init(ccmParameters.getEncoded()); + + byte[] keyBytes = generateKey(pbes2Parameters.getKeyDerivationFunc(), purpose, ((password != null) ? password : new char[0])); + + c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), algParams); + + byte[] rv = c.doFinal(encryptedData); + return rv; + } + catch (Exception e) + { + throw new IOException(e.toString()); + } + } + + private KeyDerivationFunc generatePkbdAlgorithmIdentifier(int keySizeInBytes) + { + byte[] pbkdSalt = new byte[512 / 8]; + getDefaultSecureRandom().nextBytes(pbkdSalt); + return new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(pbkdSalt, 1024, keySizeInBytes, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE))); + } + + public static class Std + extends BcFKSKeyStoreSpi + { + public Std() + { + super(new BouncyCastleProvider()); + } + } + + public static class Def + extends BcFKSKeyStoreSpi + { + public Def() + { + super(null); + } + } + + private static class ExtKeyStoreException + extends KeyStoreException + { + private final Throwable cause; + + ExtKeyStoreException(String msg, Throwable cause) + { + super(msg); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } + } +} diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/BCFKS.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/BCFKS.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/BCFKS.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/BCFKS.java 2016-12-08 02:26:56.000000000 +0000 @@ -0,0 +1,23 @@ +package org.bouncycastle.jcajce.provider.keystore; + +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; + +public class BCFKS +{ + private static final String PREFIX = "org.bouncycastle.jcajce.provider.keystore" + ".bcfks."; + + public static class Mappings + extends AsymmetricAlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("KeyStore.BCFKS", PREFIX + "BcFKSKeyStoreSpi$Std"); + provider.addAlgorithm("KeyStore.BCFKS-DEF", PREFIX + "BcFKSKeyStoreSpi$Def"); + } + } +} diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java 2015-11-09 22:13:35.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java 2016-12-22 00:46:13.000000000 +0000 @@ -88,7 +88,7 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.jcajce.PKCS12Key; import org.bouncycastle.jcajce.PKCS12StoreParameter; import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec; @@ -226,7 +226,7 @@ private static byte[] getDigest(SubjectPublicKeyInfo spki) { - Digest digest = new SHA1Digest(); + Digest digest = DigestFactory.createSHA1(); byte[] resBuf = new byte[digest.getDigestSize()]; byte[] bytes = spki.getPublicKeyData().getBytes(); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java 2015-08-30 07:30:33.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java 2016-12-08 03:30:18.000000000 +0000 @@ -16,7 +16,11 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherKeyGenerator; -import org.bouncycastle.crypto.engines.AESFastEngine; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.engines.AESWrapEngine; import org.bouncycastle.crypto.engines.RFC3211WrapEngine; import org.bouncycastle.crypto.engines.RFC5649WrapEngine; @@ -34,10 +38,12 @@ import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher; import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac; +import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory; import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher; import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider; import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters; import org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory; +import org.bouncycastle.jcajce.spec.AEADParameterSpec; public final class AES { @@ -56,7 +62,7 @@ { public BlockCipher get() { - return new AESFastEngine(); + return new AESEngine(); } }); } @@ -67,7 +73,7 @@ { public CBC() { - super(new CBCBlockCipher(new AESFastEngine()), 128); + super(new CBCBlockCipher(new AESEngine()), 128); } } @@ -76,7 +82,7 @@ { public CFB() { - super(new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 128)), 128); + super(new BufferedBlockCipher(new CFBBlockCipher(new AESEngine(), 128)), 128); } } @@ -85,7 +91,7 @@ { public OFB() { - super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128); + super(new BufferedBlockCipher(new OFBBlockCipher(new AESEngine(), 128)), 128); } } @@ -94,7 +100,7 @@ { public GCM() { - super(new GCMBlockCipher(new AESFastEngine())); + super(new GCMBlockCipher(new AESEngine())); } } @@ -103,7 +109,7 @@ { public CCM() { - super(new CCMBlockCipher(new AESFastEngine()), false, 16); + super(new CCMBlockCipher(new AESEngine()), false, 16); } } @@ -112,7 +118,7 @@ { public AESCMAC() { - super(new CMac(new AESFastEngine())); + super(new CMac(new AESEngine())); } } @@ -121,7 +127,81 @@ { public AESGMAC() { - super(new GMac(new GCMBlockCipher(new AESFastEngine()))); + super(new GMac(new GCMBlockCipher(new AESEngine()))); + } + } + + public static class AESCCMMAC + extends BaseMac + { + public AESCCMMAC() + { + super(new CCMMac()); + } + + private static class CCMMac + implements Mac + { + private final CCMBlockCipher ccm = new CCMBlockCipher(new AESEngine()); + + private int macLength = 8; + + public void init(CipherParameters params) + throws IllegalArgumentException + { + ccm.init(true, params); + + this.macLength = ccm.getMac().length; + } + + public String getAlgorithmName() + { + return ccm.getAlgorithmName() + "Mac"; + } + + public int getMacSize() + { + return macLength; + } + + public void update(byte in) + throws IllegalStateException + { + ccm.processAADByte(in); + } + + public void update(byte[] in, int inOff, int len) + throws DataLengthException, IllegalStateException + { + ccm.processAADBytes(in, inOff, len); + } + + public int doFinal(byte[] out, int outOff) + throws DataLengthException, IllegalStateException + { + try + { + return ccm.doFinal(out, 0); + } + catch (InvalidCipherTextException e) + { + throw new IllegalStateException("exception on doFinal(): " + e.toString()); + } + } + + public void reset() + { + ccm.reset(); + } + } + } + + static public class KeyFactory + extends BaseSecretKeyFactory + { + public KeyFactory() + { + super("AES", null); } } @@ -130,7 +210,7 @@ { public Poly1305() { - super(new org.bouncycastle.crypto.macs.Poly1305(new AESFastEngine())); + super(new org.bouncycastle.crypto.macs.Poly1305(new AESEngine())); } } @@ -157,7 +237,7 @@ { public RFC3211Wrap() { - super(new RFC3211WrapEngine(new AESFastEngine()), 16); + super(new RFC3211WrapEngine(new AESEngine()), 16); } } @@ -166,7 +246,7 @@ { public RFC5649Wrap() { - super(new RFC5649WrapEngine(new AESFastEngine())); + super(new RFC5649WrapEngine(new AESEngine())); } } @@ -178,7 +258,7 @@ { public PBEWithAESCBC() { - super(new CBCBlockCipher(new AESFastEngine())); + super(new CBCBlockCipher(new AESEngine())); } } @@ -190,7 +270,7 @@ { public PBEWithSHA1AESCBC128() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 128, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 128, 16); } } @@ -199,7 +279,7 @@ { public PBEWithSHA1AESCBC192() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 192, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 192, 16); } } @@ -208,7 +288,7 @@ { public PBEWithSHA1AESCBC256() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 256, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 256, 16); } } @@ -220,7 +300,7 @@ { public PBEWithSHA256AESCBC128() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 128, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 128, 16); } } @@ -229,7 +309,7 @@ { public PBEWithSHA256AESCBC192() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 192, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 192, 16); } } @@ -238,7 +318,7 @@ { public PBEWithSHA256AESCBC256() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 256, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 256, 16); } } @@ -437,6 +517,7 @@ SecureRandom random) throws InvalidAlgorithmParameterException { + // TODO: add support for GCMParameterSpec as a template. throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation."); } @@ -475,6 +556,7 @@ SecureRandom random) throws InvalidAlgorithmParameterException { + // TODO: add support for GCMParameterSpec as a template. throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation."); } @@ -494,7 +576,7 @@ try { params = createParametersInstance("GCM"); - params.init(new GCMParameters(nonce, 12).getEncoded()); + params.init(new GCMParameters(nonce, 16).getEncoded()); } catch (Exception e) { @@ -526,6 +608,10 @@ { gcmParams = GcmSpecUtil.extractGcmParameters(paramSpec); } + else if (paramSpec instanceof AEADParameterSpec) + { + gcmParams = new GCMParameters(((AEADParameterSpec)paramSpec).getNonce(), ((AEADParameterSpec)paramSpec).getMacSizeInBits() / 8); + } else { throw new InvalidParameterSpecException("AlgorithmParameterSpec class not recognized: " + paramSpec.getClass().getName()); @@ -580,7 +666,11 @@ { return GcmSpecUtil.extractGcmSpec(gcmParams.toASN1Primitive()); } - return new IvParameterSpec(gcmParams.getNonce()); + return new AEADParameterSpec(gcmParams.getNonce(), gcmParams.getIcvLen() * 8); + } + if (paramSpec == AEADParameterSpec.class) + { + return new AEADParameterSpec(gcmParams.getNonce(), gcmParams.getIcvLen() * 8); } if (paramSpec == IvParameterSpec.class) { @@ -603,6 +693,10 @@ { ccmParams = CCMParameters.getInstance(GcmSpecUtil.extractGcmParameters(paramSpec)); } + else if (paramSpec instanceof AEADParameterSpec) + { + ccmParams = new CCMParameters(((AEADParameterSpec)paramSpec).getNonce(), ((AEADParameterSpec)paramSpec).getMacSizeInBits() / 8); + } else { throw new InvalidParameterSpecException("AlgorithmParameterSpec class not recognized: " + paramSpec.getClass().getName()); @@ -657,7 +751,11 @@ { return GcmSpecUtil.extractGcmSpec(ccmParams.toASN1Primitive()); } - return new IvParameterSpec(ccmParams.getNonce()); + return new AEADParameterSpec(ccmParams.getNonce(), ccmParams.getIcvLen() * 8); + } + if (paramSpec == AEADParameterSpec.class) + { + return new AEADParameterSpec(ccmParams.getNonce(), ccmParams.getIcvLen() * 8); } if (paramSpec == IvParameterSpec.class) { @@ -787,7 +885,12 @@ provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_CCM, PREFIX + "$KeyGen256"); provider.addAlgorithm("Mac.AESCMAC", PREFIX + "$AESCMAC"); - + + provider.addAlgorithm("Mac.AESCCMMAC", PREFIX + "$AESCCMMAC"); + provider.addAlgorithm("Alg.Alias.Mac." + NISTObjectIdentifiers.id_aes128_CCM.getId(), "AESCCMMAC"); + provider.addAlgorithm("Alg.Alias.Mac." + NISTObjectIdentifiers.id_aes192_CCM.getId(), "AESCCMMAC"); + provider.addAlgorithm("Alg.Alias.Mac." + NISTObjectIdentifiers.id_aes256_CCM.getId(), "AESCCMMAC"); + provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc, "PBEWITHSHAAND128BITAES-CBC-BC"); provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc, "PBEWITHSHAAND192BITAES-CBC-BC"); provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc, "PBEWITHSHAAND256BITAES-CBC-BC"); @@ -830,7 +933,10 @@ provider.addAlgorithm("Cipher.PBEWITHMD5AND128BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC"); provider.addAlgorithm("Cipher.PBEWITHMD5AND192BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC"); provider.addAlgorithm("Cipher.PBEWITHMD5AND256BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC"); - + + provider.addAlgorithm("SecretKeyFactory.AES", PREFIX + "$KeyFactory"); + provider.addAlgorithm("SecretKeyFactory", NISTObjectIdentifiers.aes, PREFIX + "$KeyFactory"); + provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND128BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And128BitAESCBCOpenSSL"); provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND192BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And192BitAESCBCOpenSSL"); provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND256BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And256BitAESCBCOpenSSL"); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java 2013-09-18 01:13:22.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java 2016-08-31 00:44:19.000000000 +0000 @@ -1,6 +1,7 @@ package org.bouncycastle.jcajce.provider.symmetric; import org.bouncycastle.crypto.CipherKeyGenerator; +import org.bouncycastle.crypto.engines.ChaCha7539Engine; import org.bouncycastle.crypto.engines.ChaChaEngine; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; @@ -31,6 +32,24 @@ } } + public static class Base7539 + extends BaseStreamCipher + { + public Base7539() + { + super(new ChaCha7539Engine(), 12); + } + } + + public static class KeyGen7539 + extends BaseKeyGenerator + { + public KeyGen7539() + { + super("ChaCha7539", 256, new CipherKeyGenerator()); + } + } + public static class Mappings extends AlgorithmProvider { @@ -46,6 +65,8 @@ provider.addAlgorithm("Cipher.CHACHA", PREFIX + "$Base"); provider.addAlgorithm("KeyGenerator.CHACHA", PREFIX + "$KeyGen"); + provider.addAlgorithm("Cipher.CHACHA7539", PREFIX + "$Base7539"); + provider.addAlgorithm("KeyGenerator.CHACHA7539", PREFIX + "$KeyGen7539"); } } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java 2015-07-03 02:50:45.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java 2016-12-08 03:21:27.000000000 +0000 @@ -12,6 +12,7 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.crypto.KeyGenerationParameters; import org.bouncycastle.crypto.engines.DESedeEngine; @@ -398,6 +399,8 @@ provider.addAlgorithm("SecretKeyFactory.DESEDE", PREFIX + "$KeyFactory"); + provider.addAlgorithm("SecretKeyFactory", OIWObjectIdentifiers.desEDE, PREFIX + "$KeyFactory"); + provider.addAlgorithm("Mac.DESEDECMAC", PREFIX + "$CMAC"); provider.addAlgorithm("Mac.DESEDEMAC", PREFIX + "$CBCMAC"); provider.addAlgorithm("Alg.Alias.Mac.DESEDE", "DESEDEMAC"); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Poly1305.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Poly1305.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Poly1305.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Poly1305.java 2016-08-31 01:12:35.000000000 +0000 @@ -0,0 +1,49 @@ +package org.bouncycastle.jcajce.provider.symmetric; + +import org.bouncycastle.crypto.generators.Poly1305KeyGenerator; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; +import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac; +import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; + +public class Poly1305 +{ + private Poly1305() + { + } + + public static class Mac + extends BaseMac + { + public Mac() + { + super(new org.bouncycastle.crypto.macs.Poly1305()); + } + } + + public static class KeyGen + extends BaseKeyGenerator + { + public KeyGen() + { + super("Poly1305", 256, new Poly1305KeyGenerator()); + } + } + + public static class Mappings + extends AlgorithmProvider + { + private static final String PREFIX = Poly1305.class.getName(); + + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("Mac.POLY1305", PREFIX + "$Mac"); + + provider.addAlgorithm("KeyGenerator.POLY1305", PREFIX + "$KeyGen"); + } + } +} diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java 2015-07-03 02:10:30.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java 2016-08-19 02:34:21.000000000 +0000 @@ -345,7 +345,7 @@ Class paramSpec) throws InvalidParameterSpecException { - if (paramSpec == RC2ParameterSpec.class) + if (paramSpec == RC2ParameterSpec.class || paramSpec == AlgorithmParameterSpec.class) { if (parameterVersion != -1) { @@ -360,7 +360,7 @@ } } - if (paramSpec == IvParameterSpec.class) + if (paramSpec == IvParameterSpec.class || paramSpec == AlgorithmParameterSpec.class) { return new IvParameterSpec(iv); } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/TLSKDF.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/TLSKDF.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/TLSKDF.java 2016-06-28 04:52:31.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/TLSKDF.java 2016-12-22 02:07:48.000000000 +0000 @@ -6,15 +6,13 @@ import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; -import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.Mac; -import org.bouncycastle.crypto.digests.MD5Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA384Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory; import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; @@ -77,8 +75,8 @@ private static byte[] PRF_legacy(TLSKeyMaterialSpec parameters) { - Mac md5Hmac = new HMac(new MD5Digest()); - Mac sha1HMac = new HMac(new SHA1Digest()); + Mac md5Hmac = new HMac(DigestFactory.createMD5()); + Mac sha1HMac = new HMac(DigestFactory.createSHA1()); byte[] label = Strings.toByteArray(parameters.getLabel()); byte[] labelSeed = Arrays.concatenate(label, parameters.getSeed()); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java 2016-04-06 02:56:18.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java 2016-12-16 00:23:48.000000000 +0000 @@ -63,6 +63,7 @@ import org.bouncycastle.jcajce.PBKDF1KeyWithParameters; import org.bouncycastle.jcajce.PKCS12Key; import org.bouncycastle.jcajce.PKCS12KeyWithParameters; +import org.bouncycastle.jcajce.spec.AEADParameterSpec; import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec; import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec; import org.bouncycastle.util.Strings; @@ -156,9 +157,9 @@ protected BaseBlockCipher( AEADBlockCipher engine) { - baseEngine = engine.getUnderlyingCipher(); - ivLength = baseEngine.getBlockSize(); - cipher = new AEADGenericBlockCipher(engine); + this.baseEngine = engine.getUnderlyingCipher(); + this.ivLength = baseEngine.getBlockSize(); + this.cipher = new AEADGenericBlockCipher(engine); } protected BaseBlockCipher( @@ -235,6 +236,18 @@ return null; } } + else if (aeadParams != null) + { + try + { + engineParams = createParametersInstance("GCM"); + engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize() / 8).getEncoded()); + } + catch (Exception e) + { + throw new RuntimeException(e.toString()); + } + } else if (ivParam != null) { String name = cipher.getUnderlyingCipher().getAlgorithmName(); @@ -254,18 +267,6 @@ throw new RuntimeException(e.toString()); } } - else if (aeadParams != null) - { - try - { - engineParams = createParametersInstance("GCM"); - engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize() / 8).getEncoded()); - } - catch (Exception e) - { - throw new RuntimeException(e.toString()); - } - } } return engineParams; @@ -480,7 +481,7 @@ // if (!(key instanceof SecretKey)) { - throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption."); + throw new InvalidKeyException("Key for algorithm " + ((key != null) ? key.getAlgorithm() : null) + " not suitable for symmetric enryption."); } // @@ -632,7 +633,27 @@ param = null; } - if (params instanceof IvParameterSpec) + if (params instanceof AEADParameterSpec) + { + if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher)) + { + throw new InvalidAlgorithmParameterException("AEADParameterSpec can only be used with AEAD modes."); + } + + AEADParameterSpec aeadSpec = (AEADParameterSpec)params; + + KeyParameter keyParam; + if (param instanceof ParametersWithIV) + { + keyParam = (KeyParameter)((ParametersWithIV)param).getParameters(); + } + else + { + keyParam = (KeyParameter)param; + } + param = aeadParams = new AEADParameters(keyParam, aeadSpec.getMacSizeInBits(), aeadSpec.getNonce(), aeadSpec.getAssociatedData()); + } + else if (params instanceof IvParameterSpec) { if (ivLength != 0) { @@ -795,6 +816,8 @@ } } + + if (random != null && padded) { param = new ParametersWithRandom(param, random); @@ -815,16 +838,17 @@ default: throw new InvalidParameterException("unknown opmode " + opmode + " passed"); } + + if (cipher instanceof AEADGenericBlockCipher && aeadParams == null) + { + AEADBlockCipher aeadCipher = ((AEADGenericBlockCipher)cipher).cipher; + + aeadParams = new AEADParameters((KeyParameter)ivParam.getParameters(), aeadCipher.getMac().length * 8, ivParam.getIV()); + } } catch (final Exception e) { - throw new InvalidKeyException(e.getMessage()) - { - public Throwable getCause() - { - return e; - } - }; + throw new InvalidKeyOrParametersException(e.getMessage(), e); } } @@ -1304,4 +1328,21 @@ } } } + + private static class InvalidKeyOrParametersException + extends InvalidKeyException + { + private final Throwable cause; + + InvalidKeyOrParametersException(String msg, Throwable cause) + { + super(msg); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } + } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java 2015-06-12 04:43:19.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java 2016-09-14 11:08:18.000000000 +0000 @@ -1,5 +1,6 @@ package org.bouncycastle.jcajce.provider.symmetric.util; +import java.lang.reflect.Method; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; @@ -13,18 +14,24 @@ import javax.crypto.interfaces.PBEKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEParameterSpec; +import javax.crypto.spec.RC2ParameterSpec; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.crypto.params.RC2Parameters; import org.bouncycastle.crypto.params.SkeinParameters; import org.bouncycastle.jcajce.PKCS12Key; +import org.bouncycastle.jcajce.spec.AEADParameterSpec; import org.bouncycastle.jcajce.spec.SkeinParameterSpec; public class BaseMac extends MacSpi implements PBE { + private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec"); + private Mac macEngine; private int scheme = PKCS12; @@ -121,24 +128,74 @@ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set."); } } + else + { + if (params instanceof PBEParameterSpec) + { + throw new InvalidAlgorithmParameterException("inappropriate parameter type: " + params.getClass().getName()); + } + param = new KeyParameter(key.getEncoded()); + } + + KeyParameter keyParam; + if (param instanceof ParametersWithIV) + { + keyParam = (KeyParameter)((ParametersWithIV)param).getParameters(); + } + else + { + keyParam = (KeyParameter)param; + } + + if (params instanceof AEADParameterSpec) + { + AEADParameterSpec aeadSpec = (AEADParameterSpec)params; + + param = new AEADParameters(keyParam, aeadSpec.getMacSizeInBits(), aeadSpec.getNonce(), aeadSpec.getAssociatedData()); + } else if (params instanceof IvParameterSpec) { - param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV()); + param = new ParametersWithIV(keyParam, ((IvParameterSpec)params).getIV()); + } + else if (params instanceof RC2ParameterSpec) + { + param = new ParametersWithIV(new RC2Parameters(keyParam.getKey(), ((RC2ParameterSpec)params).getEffectiveKeyBits()), ((RC2ParameterSpec)params).getIV()); } else if (params instanceof SkeinParameterSpec) { - param = new SkeinParameters.Builder(copyMap(((SkeinParameterSpec)params).getParameters())).setKey(key.getEncoded()).build(); + param = new SkeinParameters.Builder(copyMap(((SkeinParameterSpec)params).getParameters())).setKey(keyParam.getKey()).build(); } else if (params == null) { param = new KeyParameter(key.getEncoded()); } - else + else if (gcmSpecClass != null && gcmSpecClass.isAssignableFrom(params.getClass())) { - throw new InvalidAlgorithmParameterException("unknown parameter type."); + try + { + Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]); + Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]); + + param = new AEADParameters(keyParam, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0])); + } + catch (Exception e) + { + throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec."); + } + } + else if (!(params instanceof PBEParameterSpec)) + { + throw new InvalidAlgorithmParameterException("unknown parameter type: " + params.getClass().getName()); } - macEngine.init(param); + try + { + macEngine.init(param); + } + catch (Exception e) + { + throw new InvalidAlgorithmParameterException("cannot initialize MAC: " + e.getMessage()); + } } protected int engineGetMacLength() @@ -187,4 +244,18 @@ return newTable; } + + private static Class lookup(String className) + { + try + { + Class def = BaseBlockCipher.class.getClassLoader().loadClass(className); + + return def; + } + catch (Exception e) + { + return null; + } + } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java 2013-05-31 01:24:31.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java 2016-12-08 03:26:54.000000000 +0000 @@ -32,7 +32,7 @@ { if (keySpec instanceof SecretKeySpec) { - return (SecretKey)keySpec; + return new SecretKeySpec(((SecretKeySpec)keySpec).getEncoded(), algName); } throw new InvalidKeySpecException("Invalid KeySpec"); diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java 2015-07-03 04:49:36.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java 2016-11-17 23:12:14.000000000 +0000 @@ -98,7 +98,7 @@ protected int engineGetKeySize( Key key) { - return key.getEncoded().length; + return key.getEncoded().length * 8; } protected int engineGetOutputSize( diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java 2013-05-31 01:24:31.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java 2016-08-19 02:11:28.000000000 +0000 @@ -43,7 +43,7 @@ Class paramSpec) throws InvalidParameterSpecException { - if (paramSpec == IvParameterSpec.class) + if (paramSpec == IvParameterSpec.class || paramSpec == AlgorithmParameterSpec.class) { return new IvParameterSpec(iv); } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java 2016-03-16 03:25:21.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java 2016-12-22 00:30:25.000000000 +0000 @@ -11,13 +11,7 @@ import org.bouncycastle.crypto.PBEParametersGenerator; import org.bouncycastle.crypto.digests.GOST3411Digest; import org.bouncycastle.crypto.digests.MD2Digest; -import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.crypto.digests.RIPEMD160Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.digests.TigerDigest; import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator; import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; @@ -26,6 +20,7 @@ import org.bouncycastle.crypto.params.DESParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.crypto.util.DigestFactory; public interface PBE { @@ -69,10 +64,10 @@ generator = new PKCS5S1ParametersGenerator(new MD2Digest()); break; case MD5: - generator = new PKCS5S1ParametersGenerator(new MD5Digest()); + generator = new PKCS5S1ParametersGenerator(DigestFactory.createMD5()); break; case SHA1: - generator = new PKCS5S1ParametersGenerator(new SHA1Digest()); + generator = new PKCS5S1ParametersGenerator(DigestFactory.createSHA1()); break; default: throw new IllegalStateException("PKCS5 scheme 1 only supports MD2, MD5 and SHA1."); @@ -86,10 +81,10 @@ generator = new PKCS5S2ParametersGenerator(new MD2Digest()); break; case MD5: - generator = new PKCS5S2ParametersGenerator(new MD5Digest()); + generator = new PKCS5S2ParametersGenerator(DigestFactory.createMD5()); break; case SHA1: - generator = new PKCS5S2ParametersGenerator(new SHA1Digest()); + generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA1()); break; case RIPEMD160: generator = new PKCS5S2ParametersGenerator(new RIPEMD160Digest()); @@ -98,19 +93,19 @@ generator = new PKCS5S2ParametersGenerator(new TigerDigest()); break; case SHA256: - generator = new PKCS5S2ParametersGenerator(new SHA256Digest()); + generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA256()); break; case GOST3411: generator = new PKCS5S2ParametersGenerator(new GOST3411Digest()); break; case SHA224: - generator = new PKCS5S2ParametersGenerator(new SHA224Digest()); + generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA224()); break; case SHA384: - generator = new PKCS5S2ParametersGenerator(new SHA384Digest()); + generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA384()); break; case SHA512: - generator = new PKCS5S2ParametersGenerator(new SHA512Digest()); + generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA512()); break; default: throw new IllegalStateException("unknown digest scheme for PBE PKCS5S2 encryption."); @@ -124,10 +119,10 @@ generator = new PKCS12ParametersGenerator(new MD2Digest()); break; case MD5: - generator = new PKCS12ParametersGenerator(new MD5Digest()); + generator = new PKCS12ParametersGenerator(DigestFactory.createMD5()); break; case SHA1: - generator = new PKCS12ParametersGenerator(new SHA1Digest()); + generator = new PKCS12ParametersGenerator(DigestFactory.createSHA1()); break; case RIPEMD160: generator = new PKCS12ParametersGenerator(new RIPEMD160Digest()); @@ -136,11 +131,20 @@ generator = new PKCS12ParametersGenerator(new TigerDigest()); break; case SHA256: - generator = new PKCS12ParametersGenerator(new SHA256Digest()); + generator = new PKCS12ParametersGenerator(DigestFactory.createSHA256()); break; case GOST3411: generator = new PKCS12ParametersGenerator(new GOST3411Digest()); break; + case SHA224: + generator = new PKCS12ParametersGenerator(DigestFactory.createSHA224()); + break; + case SHA384: + generator = new PKCS12ParametersGenerator(DigestFactory.createSHA384()); + break; + case SHA512: + generator = new PKCS12ParametersGenerator(DigestFactory.createSHA512()); + break; default: throw new IllegalStateException("unknown digest scheme for PBE encryption."); } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/util/BadBlockException.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/util/BadBlockException.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/util/BadBlockException.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/util/BadBlockException.java 2016-08-27 02:59:38.000000000 +0000 @@ -0,0 +1,21 @@ +package org.bouncycastle.jcajce.provider.util; + +import javax.crypto.BadPaddingException; + +public class BadBlockException + extends BadPaddingException +{ + private final Throwable cause; + + public BadBlockException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java 2016-03-05 17:20:31.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java 2016-12-22 00:30:24.000000000 +0000 @@ -10,14 +10,6 @@ import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.MD5Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA3Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; -import org.bouncycastle.crypto.digests.SHA512tDigest; import org.bouncycastle.util.Strings; public class DigestFactory @@ -133,52 +125,52 @@ if (sha1.contains(digestName)) { - return new SHA1Digest(); + return org.bouncycastle.crypto.util.DigestFactory.createSHA1(); } if (md5.contains(digestName)) { - return new MD5Digest(); + return org.bouncycastle.crypto.util.DigestFactory.createMD5(); } if (sha224.contains(digestName)) { - return new SHA224Digest(); + return org.bouncycastle.crypto.util.DigestFactory.createSHA224(); } if (sha256.contains(digestName)) { - return new SHA256Digest(); + return org.bouncycastle.crypto.util.DigestFactory.createSHA256(); } if (sha384.contains(digestName)) { - return new SHA384Digest(); + return org.bouncycastle.crypto.util.DigestFactory.createSHA384(); } if (sha512.contains(digestName)) { - return new SHA512Digest(); + return org.bouncycastle.crypto.util.DigestFactory.createSHA512(); } if (sha512_224.contains(digestName)) { - return new SHA512tDigest(224); + return org.bouncycastle.crypto.util.DigestFactory.createSHA512_224(); } if (sha512_256.contains(digestName)) { - return new SHA512tDigest(256); + return org.bouncycastle.crypto.util.DigestFactory.createSHA512_256(); } if (sha3_224.contains(digestName)) { - return new SHA3Digest(224); + return org.bouncycastle.crypto.util.DigestFactory.createSHA3_224(); } if (sha3_256.contains(digestName)) { - return new SHA3Digest(256); + return org.bouncycastle.crypto.util.DigestFactory.createSHA3_256(); } if (sha3_384.contains(digestName)) { - return new SHA3Digest(384); + return org.bouncycastle.crypto.util.DigestFactory.createSHA3_384(); } if (sha3_512.contains(digestName)) { - return new SHA3Digest(512); + return org.bouncycastle.crypto.util.DigestFactory.createSHA3_512(); } return null; diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/spec/AEADParameterSpec.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/spec/AEADParameterSpec.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/spec/AEADParameterSpec.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/spec/AEADParameterSpec.java 2015-09-12 03:35:58.000000000 +0000 @@ -0,0 +1,73 @@ +package org.bouncycastle.jcajce.spec; + +import javax.crypto.spec.IvParameterSpec; + +import org.bouncycastle.util.Arrays; + +/** + * ParameterSpec for AEAD modes which allows associated data to be added via an algorithm parameter spec.In normal + * circumstances you would only want to use this if you had to work with the pre-JDK1.7 Cipher class as associated + * data is ignored for the purposes of returning a Cipher's parameters. + */ +public class AEADParameterSpec + extends IvParameterSpec +{ + private final byte[] associatedData; + private final int macSizeInBits; + + /** + * Base constructor. + * + * @param nonce nonce/iv to be used + * @param macSizeInBits macSize in bits + */ + public AEADParameterSpec(byte[] nonce, int macSizeInBits) + { + this(nonce, macSizeInBits, null); + } + + /** + * Base constructor with prepended associated data. + * + * @param nonce nonce/iv to be used + * @param macSizeInBits macSize in bits + * @param associatedData associated data to be prepended to the cipher stream. + */ + public AEADParameterSpec(byte[] nonce, int macSizeInBits, byte[] associatedData) + { + super(nonce); + + this.macSizeInBits = macSizeInBits; + this.associatedData = Arrays.clone(associatedData); + } + + /** + * Return the size of the MAC associated with this parameter spec. + * + * @return the MAC size in bits. + */ + public int getMacSizeInBits() + { + return macSizeInBits; + } + + /** + * Return the associated data associated with this parameter spec. + * + * @return the associated data, null if there isn't any. + */ + public byte[] getAssociatedData() + { + return Arrays.clone(associatedData); + } + + /** + * Return the nonce (same as IV) associated with this parameter spec. + * + * @return the nonce/IV. + */ + public byte[] getNonce() + { + return getIV(); + } +} diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java 2015-02-14 03:27:02.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java 2016-11-04 00:39:14.000000000 +0000 @@ -6,6 +6,7 @@ import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.security.Signature; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; @@ -96,4 +97,10 @@ { return CertificateFactory.getInstance(algorithm); } + + public SecureRandom createSecureRandom(String algorithm) + throws NoSuchAlgorithmException + { + return SecureRandom.getInstance(algorithm); + } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java 2015-02-14 03:28:36.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java 2016-11-04 00:43:44.000000000 +0000 @@ -7,6 +7,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.security.SecureRandom; import java.security.Signature; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; @@ -59,4 +60,7 @@ CertificateFactory createCertificateFactory(String algorithm) throws NoSuchProviderException, CertificateException; + + SecureRandom createSecureRandom(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException; } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java 2015-02-14 03:27:02.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java 2016-11-04 00:43:44.000000000 +0000 @@ -7,6 +7,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.security.SecureRandom; import java.security.Signature; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; @@ -103,4 +104,10 @@ { return CertificateFactory.getInstance(algorithm, providerName); } + + public SecureRandom createSecureRandom(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return SecureRandom.getInstance(algorithm, providerName); + } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java 2015-02-14 03:27:02.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java 2016-11-04 00:43:44.000000000 +0000 @@ -7,6 +7,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Provider; +import java.security.SecureRandom; import java.security.Signature; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; @@ -103,4 +104,10 @@ { return CertificateFactory.getInstance(algorithm, provider); } + + public SecureRandom createSecureRandom(String algorithm) + throws NoSuchAlgorithmException + { + return SecureRandom.getInstance(algorithm, provider); + } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java 2013-04-11 01:56:56.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java 2016-10-18 03:31:16.000000000 +0000 @@ -1,6 +1,11 @@ package org.bouncycastle.jce.provider; import java.security.Permission; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import javax.crypto.spec.DHParameterSpec; @@ -21,12 +26,18 @@ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS); private static Permission BC_DH_PERMISSION = new ProviderConfigurationPermission( BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.DH_DEFAULT_PARAMS); + private static Permission BC_EC_CURVE_PERMISSION = new ProviderConfigurationPermission( + BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.ACCEPTABLE_EC_CURVES); + private static Permission BC_ADDITIONAL_EC_CURVE_PERMISSION = new ProviderConfigurationPermission( + BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.ADDITIONAL_EC_PARAMETERS); private ThreadLocal ecThreadSpec = new ThreadLocal(); private ThreadLocal dhThreadSpec = new ThreadLocal(); private volatile ECParameterSpec ecImplicitCaParams; private volatile Object dhDefaultParams; + private volatile Set acceptableNamedCurves = new HashSet(); + private volatile Map additionalECParameters = new HashMap(); void setParameter(String parameterName, Object parameter) { @@ -118,6 +129,24 @@ throw new IllegalArgumentException("not a valid DHParameterSpec or DHParameterSpec[]"); } } + else if (parameterName.equals(ConfigurableProvider.ACCEPTABLE_EC_CURVES)) + { + if (securityManager != null) + { + securityManager.checkPermission(BC_EC_CURVE_PERMISSION); + } + + this.acceptableNamedCurves = (Set)parameter; + } + else if (parameterName.equals(ConfigurableProvider.ADDITIONAL_EC_PARAMETERS)) + { + if (securityManager != null) + { + securityManager.checkPermission(BC_ADDITIONAL_EC_CURVE_PERMISSION); + } + + this.additionalECParameters = (Map)parameter; + } } public ECParameterSpec getEcImplicitlyCa() @@ -164,4 +193,14 @@ return null; } + + public Set getAcceptableNamedCurves() + { + return Collections.unmodifiableSet(acceptableNamedCurves); + } + + public Map getAdditionalECParameters() + { + return Collections.unmodifiableMap(additionalECParameters); + } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java 2016-08-15 21:57:15.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java 2016-12-16 22:32:33.000000000 +0000 @@ -44,7 +44,7 @@ public final class BouncyCastleProvider extends Provider implements ConfigurableProvider { - private static String info = "BouncyCastle Security Provider v1.55"; + private static String info = "BouncyCastle Security Provider v1.56"; public static final String PROVIDER_NAME = "BC"; @@ -64,7 +64,7 @@ private static final String[] SYMMETRIC_MACS = { - "SipHash" + "SipHash", "Poly1305" }; private static final String[] SYMMETRIC_CIPHERS = @@ -108,7 +108,16 @@ private static final String KEYSTORE_PACKAGE = "org.bouncycastle.jcajce.provider.keystore."; private static final String[] KEYSTORES = { - "BC", "PKCS12" + "BC", "BCFKS", "PKCS12" + }; + + /* + * Configurable secure random + */ + private static final String SECURE_RANDOM_PACKAGE = "org.bouncycastle.jcajce.provider.drbg."; + private static final String[] SECURE_RANDOMS = + { + "DRBG" }; /** @@ -118,7 +127,7 @@ */ public BouncyCastleProvider() { - super(PROVIDER_NAME, 1.55, info); + super(PROVIDER_NAME, 1.56, info); AccessController.doPrivileged(new PrivilegedAction() { @@ -146,6 +155,8 @@ loadAlgorithms(KEYSTORE_PACKAGE, KEYSTORES); + loadAlgorithms(SECURE_RANDOM_PACKAGE, SECURE_RANDOMS); + // // X509Store // diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java 2015-11-10 03:39:59.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java 2016-11-25 00:00:45.000000000 +0000 @@ -66,6 +66,9 @@ import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; +/** + * @deprecated Do not use this class directly - either use org.bouncycastle.cert (bcpkix) or CertificateFactory. + */ public class X509CertificateObject extends X509Certificate implements PKCS12BagAttributeCarrier diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java 2015-11-10 04:00:52.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java 2016-11-25 00:00:45.000000000 +0000 @@ -53,6 +53,7 @@ * CRL Number * Delta CRL Indicator (critical) * Issuing Distribution Point (critical) + * @deprecated Do not use this class directly - either use org.bouncycastle.cert (bcpkix) or CertificateFactory. */ public class X509CRLObject extends X509CRL diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java 2015-02-19 05:21:10.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java 2016-08-27 00:56:10.000000000 +0000 @@ -33,24 +33,6 @@ this(derivation, encoding, macKeySize, -1, null, false); } - - /** - * Set the IES engine parameters. - * - * @param derivation the optional derivation vector for the KDF. - * @param encoding the optional encoding vector for the KDF. - * @param macKeySize the key size (in bits) for the MAC. - * @param cipherKeySize the key size (in bits) for the block cipher. - */ - public IESParameterSpec( - byte[] derivation, - byte[] encoding, - int macKeySize, - int cipherKeySize) - { - this(derivation, encoding, macKeySize, cipherKeySize, null, false); - } - /** * Set the IES engine parameters. * diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java 2016-08-15 22:22:19.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java 2016-12-16 22:52:07.000000000 +0000 @@ -21,7 +21,7 @@ extends Provider implements ConfigurableProvider { - private static String info = "BouncyCastle Post-Quantum Security Provider v1.55"; + private static String info = "BouncyCastle Post-Quantum Security Provider v1.56"; public static String PROVIDER_NAME = "BCPQC"; @@ -46,7 +46,7 @@ */ public BouncyCastlePQCProvider() { - super(PROVIDER_NAME, 1.55, info); + super(PROVIDER_NAME, 1.56, info); AccessController.doPrivileged(new PrivilegedAction() { diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java 2016-03-31 02:54:39.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java 2016-12-22 02:37:12.000000000 +0000 @@ -17,8 +17,8 @@ import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters; import org.bouncycastle.pqc.crypto.mceliece.McElieceFujisakiCipher; import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher; @@ -205,7 +205,7 @@ { public McElieceFujisaki() { - super(new SHA1Digest(), new McElieceFujisakiCipher()); + super(DigestFactory.createSHA1(), new McElieceFujisakiCipher()); } } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java 2012-12-03 04:48:52.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java 2016-12-22 02:37:12.000000000 +0000 @@ -17,12 +17,8 @@ import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters; import org.bouncycastle.pqc.crypto.mceliece.McElieceKobaraImaiCipher; import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher; @@ -263,7 +259,7 @@ { public McElieceKobaraImai() { - super(new SHA1Digest(), new McElieceKobaraImaiCipher()); + super(DigestFactory.createSHA1(), new McElieceKobaraImaiCipher()); } } @@ -272,7 +268,7 @@ { public McElieceKobaraImai224() { - super(new SHA224Digest(), new McElieceKobaraImaiCipher()); + super(DigestFactory.createSHA224(), new McElieceKobaraImaiCipher()); } } @@ -281,7 +277,7 @@ { public McElieceKobaraImai256() { - super(new SHA256Digest(), new McElieceKobaraImaiCipher()); + super(DigestFactory.createSHA256(), new McElieceKobaraImaiCipher()); } } @@ -290,7 +286,7 @@ { public McElieceKobaraImai384() { - super(new SHA384Digest(), new McElieceKobaraImaiCipher()); + super(DigestFactory.createSHA384(), new McElieceKobaraImaiCipher()); } } @@ -299,7 +295,7 @@ { public McElieceKobaraImai512() { - super(new SHA512Digest(), new McElieceKobaraImaiCipher()); + super(DigestFactory.createSHA512(), new McElieceKobaraImaiCipher()); } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java 2012-12-03 04:49:14.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java 2016-12-22 02:37:12.000000000 +0000 @@ -17,12 +17,8 @@ import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters; import org.bouncycastle.pqc.crypto.mceliece.McEliecePointchevalCipher; import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher; @@ -203,7 +199,7 @@ { public McEliecePointcheval() { - super(new SHA1Digest(), new McEliecePointchevalCipher()); + super(DigestFactory.createSHA1(), new McEliecePointchevalCipher()); } } @@ -212,7 +208,7 @@ { public McEliecePointcheval224() { - super(new SHA224Digest(), new McEliecePointchevalCipher()); + super(DigestFactory.createSHA224(), new McEliecePointchevalCipher()); } } @@ -221,7 +217,7 @@ { public McEliecePointcheval256() { - super(new SHA256Digest(), new McEliecePointchevalCipher()); + super(DigestFactory.createSHA256(), new McEliecePointchevalCipher()); } } @@ -230,7 +226,7 @@ { public McEliecePointcheval384() { - super(new SHA384Digest(), new McEliecePointchevalCipher()); + super(DigestFactory.createSHA384(), new McEliecePointchevalCipher()); } } @@ -239,7 +235,7 @@ { public McEliecePointcheval512() { - super(new SHA512Digest(), new McEliecePointchevalCipher()); + super(DigestFactory.createSHA512(), new McEliecePointchevalCipher()); } } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java 2016-04-01 00:33:30.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java 2016-12-22 02:37:12.000000000 +0000 @@ -5,11 +5,7 @@ import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.util.DigestFactory; class Utils { @@ -43,23 +39,23 @@ { if (digest.getAlgorithm().equals(OIWObjectIdentifiers.idSHA1)) { - return new SHA1Digest(); + return DigestFactory.createSHA1(); } if (digest.getAlgorithm().equals(NISTObjectIdentifiers.id_sha224)) { - return new SHA224Digest(); + return DigestFactory.createSHA224(); } if (digest.getAlgorithm().equals(NISTObjectIdentifiers.id_sha256)) { - return new SHA256Digest(); + return DigestFactory.createSHA256(); } if (digest.getAlgorithm().equals(NISTObjectIdentifiers.id_sha384)) { - return new SHA384Digest(); + return DigestFactory.createSHA384(); } if (digest.getAlgorithm().equals(NISTObjectIdentifiers.id_sha512)) { - return new SHA512Digest(); + return DigestFactory.createSHA512(); } throw new IllegalArgumentException("unrecognised OID in digest algorithm identifier: " + digest.getAlgorithm()); } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyPairGeneratorSpi.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyPairGeneratorSpi.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyPairGeneratorSpi.java 2016-02-23 05:24:18.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyPairGeneratorSpi.java 2016-08-29 02:00:58.000000000 +0000 @@ -28,6 +28,10 @@ int strength, SecureRandom random) { + if (strength != 1024) + { + throw new IllegalArgumentException("strength must be 1024 bits"); + } engine.init(new KeyGenerationParameters(random, 1024)); initialised = true; } @@ -37,8 +41,7 @@ SecureRandom random) throws InvalidAlgorithmParameterException { - engine.init(new KeyGenerationParameters(random, 1024)); - initialised = true; + throw new InvalidAlgorithmParameterException("parameter object not recognised"); } public KeyPair generateKeyPair() diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java 2016-08-17 03:44:27.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java 2016-10-05 20:18:31.000000000 +0000 @@ -1,5 +1,6 @@ package org.bouncycastle.x509; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.math.BigInteger; import java.security.GeneralSecurityException; @@ -11,7 +12,6 @@ import java.security.SecureRandom; import java.security.SignatureException; import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; import java.util.Date; import java.util.Iterator; @@ -19,21 +19,21 @@ import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.Certificate; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.TBSCertificate; import org.bouncycastle.asn1.x509.Time; import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator; import org.bouncycastle.asn1.x509.X509Name; +import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory; import org.bouncycastle.jcajce.util.BCJcaJceHelper; import org.bouncycastle.jcajce.util.JcaJceHelper; import org.bouncycastle.jce.X509Principal; -import org.bouncycastle.jce.provider.X509CertificateObject; /** * class to produce an X.509 Version 1 certificate. @@ -42,6 +42,7 @@ public class X509V1CertificateGenerator { private final JcaJceHelper bcHelper = new BCJcaJceHelper(); // needed to force provider loading + private final CertificateFactory certificateFactory = new CertificateFactory(); private V1TBSCertificateGenerator tbsGen; private ASN1ObjectIdentifier sigOID; @@ -357,9 +358,10 @@ try { - return new X509CertificateObject(Certificate.getInstance(new DERSequence(v))); + return (X509Certificate)certificateFactory.engineGenerateCertificate( + new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER))); } - catch (CertificateParsingException e) + catch (Exception e) { throw new ExtCertificateEncodingException("exception producing certificate object", e); } diff -Nru bouncycastle-1.55/prov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java bouncycastle-1.56/prov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java --- bouncycastle-1.55/prov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java 2016-08-17 03:44:27.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java 2016-10-05 20:18:31.000000000 +0000 @@ -1,5 +1,6 @@ package org.bouncycastle.x509; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.math.BigInteger; import java.security.GeneralSecurityException; @@ -20,23 +21,23 @@ import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.Certificate; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.TBSCertificate; import org.bouncycastle.asn1.x509.Time; import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; import org.bouncycastle.asn1.x509.X509ExtensionsGenerator; import org.bouncycastle.asn1.x509.X509Name; +import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory; import org.bouncycastle.jcajce.util.BCJcaJceHelper; import org.bouncycastle.jcajce.util.JcaJceHelper; import org.bouncycastle.jce.X509Principal; -import org.bouncycastle.jce.provider.X509CertificateObject; import org.bouncycastle.x509.extension.X509ExtensionUtil; /** @@ -46,6 +47,7 @@ public class X509V3CertificateGenerator { private final JcaJceHelper bcHelper = new BCJcaJceHelper(); // needed to force provider loading + private final CertificateFactory certificateFactory = new CertificateFactory(); private V3TBSCertificateGenerator tbsGen; private ASN1ObjectIdentifier sigOID; @@ -445,7 +447,7 @@ { return generateJcaObject(tbsCert, signature); } - catch (CertificateParsingException e) + catch (Exception e) { throw new ExtCertificateEncodingException("exception producing certificate object", e); } @@ -490,7 +492,7 @@ { return generateJcaObject(tbsCert, signature); } - catch (CertificateParsingException e) + catch (Exception e) { throw new ExtCertificateEncodingException("exception producing certificate object", e); } @@ -507,7 +509,7 @@ } private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature) - throws CertificateParsingException + throws Exception { ASN1EncodableVector v = new ASN1EncodableVector(); @@ -515,7 +517,8 @@ v.add(sigAlgId); v.add(new DERBitString(signature)); - return new X509CertificateObject(Certificate.getInstance(new DERSequence(v))); + return (X509Certificate)certificateFactory.engineGenerateCertificate( + new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER))); } /** diff -Nru bouncycastle-1.55/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java bouncycastle-1.56/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java --- bouncycastle-1.55/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java 2016-12-21 09:26:26.000000000 +0000 @@ -0,0 +1,106 @@ +package org.bouncycastle.jcajce.util; + +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + +import javax.crypto.Cipher; +import javax.crypto.KeyAgreement; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKeyFactory; + +/** + * {@link JcaJceHelper} that obtains all algorithms using the default JCA/JCE mechanism (i.e. + * without specifying a provider). + */ +public class DefaultJcaJceHelper + implements JcaJceHelper +{ + public Cipher createCipher( + String algorithm) + throws NoSuchAlgorithmException, NoSuchPaddingException + { + return Cipher.getInstance(algorithm); + } + + public Mac createMac(String algorithm) + throws NoSuchAlgorithmException + { + return Mac.getInstance(algorithm); + } + + public KeyAgreement createKeyAgreement(String algorithm) + throws NoSuchAlgorithmException + { + return KeyAgreement.getInstance(algorithm); + } + + public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm) + throws NoSuchAlgorithmException + { + return AlgorithmParameterGenerator.getInstance(algorithm); + } + + public AlgorithmParameters createAlgorithmParameters(String algorithm) + throws NoSuchAlgorithmException + { + return AlgorithmParameters.getInstance(algorithm); + } + + public KeyGenerator createKeyGenerator(String algorithm) + throws NoSuchAlgorithmException + { + return KeyGenerator.getInstance(algorithm); + } + + public KeyFactory createKeyFactory(String algorithm) + throws NoSuchAlgorithmException + { + return KeyFactory.getInstance(algorithm); + } + + public SecretKeyFactory createSecretKeyFactory(String algorithm) + throws NoSuchAlgorithmException + { + return SecretKeyFactory.getInstance(algorithm); + } + + public KeyPairGenerator createKeyPairGenerator(String algorithm) + throws NoSuchAlgorithmException + { + return KeyPairGenerator.getInstance(algorithm); + } + + public MessageDigest createDigest(String algorithm) + throws NoSuchAlgorithmException + { + return MessageDigest.getInstance(algorithm); + } + + public Signature createSignature(String algorithm) + throws NoSuchAlgorithmException + { + return Signature.getInstance(algorithm); + } + + public CertificateFactory createCertificateFactory(String algorithm) + throws CertificateException + { + return CertificateFactory.getInstance(algorithm); + } + + public SecureRandom createSecureRandom(String algorithm) + throws NoSuchAlgorithmException + { + return new SecureRandom(); + } +} diff -Nru bouncycastle-1.55/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java bouncycastle-1.56/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java --- bouncycastle-1.55/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java 2016-12-21 09:26:15.000000000 +0000 @@ -0,0 +1,113 @@ +package org.bouncycastle.jcajce.util; + +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + +import javax.crypto.Cipher; +import javax.crypto.KeyAgreement; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKeyFactory; + +/** + * {@link JcaJceHelper} that obtains all algorithms using a specific named provider. + */ +public class NamedJcaJceHelper + implements JcaJceHelper +{ + protected final String providerName; + + public NamedJcaJceHelper(String providerName) + { + this.providerName = providerName; + } + + public Cipher createCipher( + String algorithm) + throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException + { + return Cipher.getInstance(algorithm, providerName); + } + + public Mac createMac(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return Mac.getInstance(algorithm, providerName); + } + + public KeyAgreement createKeyAgreement(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return KeyAgreement.getInstance(algorithm, providerName); + } + + public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return AlgorithmParameterGenerator.getInstance(algorithm, providerName); + } + + public AlgorithmParameters createAlgorithmParameters(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return AlgorithmParameters.getInstance(algorithm, providerName); + } + + public KeyGenerator createKeyGenerator(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return KeyGenerator.getInstance(algorithm, providerName); + } + + public KeyFactory createKeyFactory(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return KeyFactory.getInstance(algorithm, providerName); + } + + public SecretKeyFactory createSecretKeyFactory(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return SecretKeyFactory.getInstance(algorithm, providerName); + } + + public KeyPairGenerator createKeyPairGenerator(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return KeyPairGenerator.getInstance(algorithm, providerName); + } + + public MessageDigest createDigest(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return MessageDigest.getInstance(algorithm, providerName); + } + + public Signature createSignature(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return Signature.getInstance(algorithm, providerName); + } + + public CertificateFactory createCertificateFactory(String algorithm) + throws CertificateException, NoSuchProviderException + { + return CertificateFactory.getInstance(algorithm, providerName); + } + + public SecureRandom createSecureRandom(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return new SecureRandom(); + } +} diff -Nru bouncycastle-1.55/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java bouncycastle-1.56/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java --- bouncycastle-1.55/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.1/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java 2016-12-21 09:26:35.000000000 +0000 @@ -0,0 +1,113 @@ +package org.bouncycastle.jcajce.util; + +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + +import javax.crypto.Cipher; +import javax.crypto.KeyAgreement; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKeyFactory; + +import org.bouncycastle.jcajce.util.JcaJceHelper; + +public class ProviderJcaJceHelper + implements JcaJceHelper +{ + protected final Provider provider; + + public ProviderJcaJceHelper(Provider provider) + { + this.provider = provider; + } + + public Cipher createCipher( + String algorithm) + throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException + { + return Cipher.getInstance(algorithm, provider.getName()); + } + + public Mac createMac(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return Mac.getInstance(algorithm, provider.getName()); + } + + public KeyAgreement createKeyAgreement(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return KeyAgreement.getInstance(algorithm, provider.getName()); + } + + public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return AlgorithmParameterGenerator.getInstance(algorithm, provider.getName()); + } + + public AlgorithmParameters createAlgorithmParameters(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return AlgorithmParameters.getInstance(algorithm, provider.getName()); + } + + public KeyGenerator createKeyGenerator(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return KeyGenerator.getInstance(algorithm, provider.getName()); + } + + public KeyFactory createKeyFactory(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return KeyFactory.getInstance(algorithm, provider.getName()); + } + + public SecretKeyFactory createSecretKeyFactory(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return SecretKeyFactory.getInstance(algorithm, provider.getName()); + } + + public KeyPairGenerator createKeyPairGenerator(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return KeyPairGenerator.getInstance(algorithm, provider.getName()); + } + + public MessageDigest createDigest(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return MessageDigest.getInstance(algorithm, provider.getName()); + } + + public Signature createSignature(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return Signature.getInstance(algorithm, provider.getName()); + } + + public CertificateFactory createCertificateFactory(String algorithm) + throws CertificateException, NoSuchProviderException + { + return CertificateFactory.getInstance(algorithm, provider.getName()); + } + + public SecureRandom createSecureRandom(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return new SecureRandom(); + } +} diff -Nru bouncycastle-1.55/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java bouncycastle-1.56/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java --- bouncycastle-1.55/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java 2015-06-08 07:41:01.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java 2016-12-20 01:53:07.000000000 +0000 @@ -1,5 +1,11 @@ package org.bouncycastle.jce.provider; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + import javax.crypto.spec.DHParameterSpec; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; @@ -11,11 +17,11 @@ { private volatile ECParameterSpec ecImplicitCaParams; private volatile Object dhDefaultParams; + private volatile Set acceptableNamedCurves = new HashSet(); + private volatile Map additionalECParameters = new HashMap(); void setParameter(String parameterName, Object parameter) { - SecurityManager securityManager = System.getSecurityManager(); - if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA)) { ECParameterSpec curveSpec; @@ -29,7 +35,7 @@ throw new IllegalArgumentException("not a valid ECParameterSpec"); } - ecImplicitCaParams = (ECParameterSpec)curveSpec; + ecImplicitCaParams = curveSpec; } else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA)) { @@ -46,7 +52,6 @@ { Object dhSpec; - if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null) { dhSpec = parameter; @@ -60,7 +65,6 @@ } else if (parameterName.equals(ConfigurableProvider.DH_DEFAULT_PARAMS)) { - if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null) { dhDefaultParams = parameter; @@ -70,6 +74,14 @@ throw new IllegalArgumentException("not a valid DHParameterSpec or DHParameterSpec[]"); } } + else if (parameterName.equals(ConfigurableProvider.ACCEPTABLE_EC_CURVES)) + { + this.acceptableNamedCurves = (Set)parameter; + } + else if (parameterName.equals(ConfigurableProvider.ADDITIONAL_EC_PARAMETERS)) + { + this.additionalECParameters = (Map)parameter; + } } public ECParameterSpec getEcImplicitlyCa() @@ -79,7 +91,7 @@ public DHParameterSpec getDHDefaultParameters(int keySize) { - Object params = dhDefaultParams; + Object params = dhDefaultParams; if (params instanceof DHParameterSpec) { @@ -105,4 +117,14 @@ return null; } + + public Set getAcceptableNamedCurves() + { + return Collections.unmodifiableSet(acceptableNamedCurves); + } + + public Map getAdditionalECParameters() + { + return Collections.unmodifiableMap(additionalECParameters); + } } diff -Nru bouncycastle-1.55/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProvider.java bouncycastle-1.56/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProvider.java --- bouncycastle-1.55/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProvider.java 2016-08-17 04:59:35.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProvider.java 2016-12-16 22:52:07.000000000 +0000 @@ -42,7 +42,7 @@ public final class BouncyCastleProvider extends Provider implements ConfigurableProvider { - private static String info = "BouncyCastle Security Provider v1.55"; + private static String info = "BouncyCastle Security Provider v1.56"; public static final String PROVIDER_NAME = "BC"; @@ -116,7 +116,7 @@ */ public BouncyCastleProvider() { - super(PROVIDER_NAME, 1.55, info); + super(PROVIDER_NAME, 1.56, info); setup(); } diff -Nru bouncycastle-1.55/prov/src/main/jdk1.2/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java bouncycastle-1.56/prov/src/main/jdk1.2/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java --- bouncycastle-1.55/prov/src/main/jdk1.2/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.2/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java 2016-12-21 09:27:12.000000000 +0000 @@ -0,0 +1,60 @@ +package org.bouncycastle.jcajce.provider.asymmetric.ec; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.PublicKey; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.x9.X962Parameters; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +class ECUtils +{ + static AsymmetricKeyParameter generatePublicKeyParameter( + PublicKey key) + throws InvalidKeyException + { + return (key instanceof BCECPublicKey) ? ((BCECPublicKey)key).engineGetKeyParameters() : ECUtil.generatePublicKeyParameter(key); + } + + static X962Parameters getDomainParametersFromName(ECParameterSpec ecSpec, boolean withCompression) + { + X962Parameters params; + + if (ecSpec instanceof ECNamedCurveParameterSpec) + { + ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName()); + + if (curveOid == null) + { + curveOid = new ASN1ObjectIdentifier(((ECNamedCurveParameterSpec)ecSpec).getName()); + } + params = new X962Parameters(curveOid); + } + else if (ecSpec == null) + { + params = new X962Parameters(DERNull.INSTANCE); + } + else + { + ECParameterSpec p = (ECParameterSpec)ecSpec; + + ECCurve curve = p.getG().getCurve(); + ECPoint generator = curve.createPoint(p.getG().getX().toBigInteger(), p.getG().getY().toBigInteger(), withCompression); + + X9ECParameters ecP = new X9ECParameters( + p.getCurve(), generator, p.getN(), p.getH(), p.getSeed()); + + params = new X962Parameters(ecP); + } + + return params; + } +} diff -Nru bouncycastle-1.55/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java bouncycastle-1.56/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java --- bouncycastle-1.55/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java 2016-08-13 05:04:50.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java 2016-12-19 02:16:14.000000000 +0000 @@ -31,6 +31,7 @@ import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import org.bouncycastle.util.Arrays; public class DSASigner extends Signature @@ -198,6 +199,16 @@ throws IOException { ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); + + if (s.size() != 2) + { + throw new IOException("malformed signature"); + } + if (!Arrays.areEqual(encoding, s.getEncoded(ASN1Encoding.DER))) + { + throw new IOException("malformed signature"); + } + return new BigInteger[]{ ((ASN1Integer)s.getObjectAt(0)).getValue(), ((ASN1Integer)s.getObjectAt(1)).getValue() diff -Nru bouncycastle-1.55/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java bouncycastle-1.56/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java --- bouncycastle-1.55/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java 2016-12-21 09:25:52.000000000 +0000 @@ -0,0 +1,968 @@ +package org.bouncycastle.jcajce.provider.keystore.bcfks; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyStoreException; +import java.security.KeyStoreSpi; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.PKCS8EncodedKeySpec; +import java.text.ParseException; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.bc.EncryptedObjectStoreData; +import org.bouncycastle.asn1.bc.EncryptedPrivateKeyData; +import org.bouncycastle.asn1.bc.EncryptedSecretKeyData; +import org.bouncycastle.asn1.bc.ObjectData; +import org.bouncycastle.asn1.bc.ObjectDataSequence; +import org.bouncycastle.asn1.bc.ObjectStore; +import org.bouncycastle.asn1.bc.ObjectStoreData; +import org.bouncycastle.asn1.bc.ObjectStoreIntegrityCheck; +import org.bouncycastle.asn1.bc.PbkdMacIntegrityCheck; +import org.bouncycastle.asn1.bc.SecretKeyData; +import org.bouncycastle.asn1.cms.CCMParameters; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import org.bouncycastle.asn1.pkcs.EncryptionScheme; +import org.bouncycastle.asn1.pkcs.KeyDerivationFunc; +import org.bouncycastle.asn1.pkcs.PBES2Parameters; +import org.bouncycastle.asn1.pkcs.PBKDF2Params; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.crypto.PBEParametersGenerator; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +class BcFKSKeyStoreSpi + extends KeyStoreSpi +{ + private static final Map oidMap = new HashMap (); + private static final Map publicAlgMap = new HashMap (); + + static + { + // Note: AES handled inline + oidMap.put("DESEDE", OIWObjectIdentifiers.desEDE); + oidMap.put("TRIPLEDES", OIWObjectIdentifiers.desEDE); + oidMap.put("TDEA", OIWObjectIdentifiers.desEDE); + oidMap.put("HMACSHA1", PKCSObjectIdentifiers.id_hmacWithSHA1); + oidMap.put("HMACSHA224", PKCSObjectIdentifiers.id_hmacWithSHA224); + oidMap.put("HMACSHA256", PKCSObjectIdentifiers.id_hmacWithSHA256); + oidMap.put("HMACSHA384", PKCSObjectIdentifiers.id_hmacWithSHA384); + oidMap.put("HMACSHA512", PKCSObjectIdentifiers.id_hmacWithSHA512); + + publicAlgMap.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); + publicAlgMap.put(X9ObjectIdentifiers.id_ecPublicKey, "EC"); + publicAlgMap.put(OIWObjectIdentifiers.elGamalAlgorithm, "DH"); + publicAlgMap.put(PKCSObjectIdentifiers.dhKeyAgreement, "DH"); + publicAlgMap.put(X9ObjectIdentifiers.id_dsa, "DSA"); + } + + private static String getPublicKeyAlg(ASN1ObjectIdentifier oid) + { + String algName = (String)publicAlgMap.get(oid); + + if (algName != null) + { + return algName; + } + + return oid.getId(); + } + + private final static BigInteger CERTIFICATE = BigInteger.valueOf(0); + private final static BigInteger PRIVATE_KEY = BigInteger.valueOf(1); + private final static BigInteger SECRET_KEY = BigInteger.valueOf(2); + private final static BigInteger PROTECTED_PRIVATE_KEY = BigInteger.valueOf(3); + private final static BigInteger PROTECTED_SECRET_KEY = BigInteger.valueOf(4); + + private final BouncyCastleProvider provider; + private final Map entries = new HashMap (); + private final Map privateKeyCache = new HashMap (); + + private AlgorithmIdentifier hmacAlgorithm; + private KeyDerivationFunc hmacPkbdAlgorithm; + private Date creationDate; + private Date lastModifiedDate; + + BcFKSKeyStoreSpi(BouncyCastleProvider provider) + { + this.provider = provider; + } + + public Key engineGetKey(String alias, char[] password) + throws NoSuchAlgorithmException, UnrecoverableKeyException + { + ObjectData ent = (ObjectData)entries.get(alias); + + if (ent != null) + { + if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY)) + { + PrivateKey cachedKey = (PrivateKey)privateKeyCache.get(alias); + if (cachedKey != null) + { + return cachedKey; + } + + EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData()); + EncryptedPrivateKeyInfo encInfo = EncryptedPrivateKeyInfo.getInstance(encPrivData.getEncryptedPrivateKeyInfo()); + + try + { + PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(decryptData("PRIVATE_KEY_ENCRYPTION", encInfo.getEncryptionAlgorithm(), password, encInfo.getEncryptedData())); + + KeyFactory kFact; + if (provider != null) + { + kFact = KeyFactory.getInstance(pInfo.getPrivateKeyAlgorithm().getAlgorithm().getId(), provider.getName()); + } + else + { + kFact = KeyFactory.getInstance(getPublicKeyAlg(pInfo.getPrivateKeyAlgorithm().getAlgorithm())); + } + + PrivateKey privateKey = kFact.generatePrivate(new PKCS8EncodedKeySpec(pInfo.getEncoded())); + + // check that the key pair and the certificate public key are consistent + // TODO: new ConsistentKeyPair(engineGetCertificate(alias).getPublicKey(), privateKey); + + privateKeyCache.put(alias, privateKey); + + return privateKey; + } + catch (Exception e) + { + throw new UnrecoverableKeyException("BCFKS KeyStore unable to recover private key (" + alias + "): " + e.getMessage()); + } + } + else if (ent.getType().equals(SECRET_KEY) || ent.getType().equals(PROTECTED_SECRET_KEY)) + { + EncryptedSecretKeyData encKeyData = EncryptedSecretKeyData.getInstance(ent.getData()); + + try + { + SecretKeyData keyData = SecretKeyData.getInstance(decryptData("SECRET_KEY_ENCRYPTION", encKeyData.getKeyEncryptionAlgorithm(), password, encKeyData.getEncryptedKeyData())); + SecretKeyFactory kFact; + if (provider != null) + { + kFact = SecretKeyFactory.getInstance(keyData.getKeyAlgorithm().getId(), provider); + } + else + { + kFact = SecretKeyFactory.getInstance(keyData.getKeyAlgorithm().getId()); + } + + return kFact.generateSecret(new SecretKeySpec(keyData.getKeyBytes(), keyData.getKeyAlgorithm().getId())); + } + catch (Exception e) + { + throw new UnrecoverableKeyException("BCFKS KeyStore unable to recover secret key (" + alias + "): " + e.getMessage()); + } + } + else + { + throw new UnrecoverableKeyException("BCFKS KeyStore unable to recover secret key (" + alias + "): type not recognized"); + } + } + + return null; + } + + public Certificate[] engineGetCertificateChain(String alias) + { + ObjectData ent = (ObjectData)entries.get(alias); + + if (ent != null) + { + if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY)) + { + EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData()); + org.bouncycastle.asn1.x509.Certificate[] certificates = encPrivData.getCertificateChain(); + Certificate[] chain = new X509Certificate[certificates.length]; + + for (int i = 0; i != chain.length; i++) + { + chain[i] = decodeCertificate(certificates[i]); + } + + return chain; + } + } + + return null; + } + + public Certificate engineGetCertificate(String s) + { + ObjectData ent = (ObjectData)entries.get(s); + + if (ent != null) + { + if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY)) + { + EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData()); + org.bouncycastle.asn1.x509.Certificate[] certificates = encPrivData.getCertificateChain(); + + return decodeCertificate(certificates[0]); + } + else if (ent.getType().equals(CERTIFICATE)) + { + return decodeCertificate(ent.getData()); + } + } + + return null; + } + + private Certificate decodeCertificate(Object cert) + { + if (provider != null) + { + try + { + CertificateFactory certFact = CertificateFactory.getInstance("X.509", provider.getName()); + + return certFact.generateCertificate(new ByteArrayInputStream(org.bouncycastle.asn1.x509.Certificate.getInstance(cert).getEncoded())); + } + catch (Exception e) + { + return null; + } + } + else + { + try + { + CertificateFactory certFact = CertificateFactory.getInstance("X.509"); + + return certFact.generateCertificate(new ByteArrayInputStream(org.bouncycastle.asn1.x509.Certificate.getInstance(cert).getEncoded())); + } + catch (Exception e) + { + return null; + } + } + } + + public Date engineGetCreationDate(String s) + { + ObjectData ent = (ObjectData)entries.get(s); + + if (ent != null) + { + try + { + // we return last modified as it represents date current state of entry was created + return ent.getLastModifiedDate().getDate(); + } + catch (ParseException e) + { + return new Date(); // it's here, but... + } + } + + return null; + } + + public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) + throws KeyStoreException + { + Date creationDate = new Date(); + Date lastEditDate = creationDate; + + ObjectData entry = (ObjectData)entries.get(alias); + if (entry != null) + { + creationDate = extractCreationDate(entry, creationDate); + } + + privateKeyCache.remove(alias); + + if (key instanceof PrivateKey) + { + if (chain == null) + { + throw new KeyStoreException("BCFKS KeyStore requires a certificate chain for private key storage."); + } + + try + { + // check that the key pair and the certificate public are consistent + // TODO: new ConsistentKeyPair(chain[0].getPublicKey(), (PrivateKey)key); + + byte[] encodedKey = key.getEncoded(); + + KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(256 / 8); + byte[] keyBytes = generateKey(pbkdAlgId, "PRIVATE_KEY_ENCRYPTION", ((password != null) ? password : new char[0])); + + Cipher c; + if (provider == null) + { + c = Cipher.getInstance("AES/CCM/NoPadding"); + } + else + { + c = Cipher.getInstance("AES/CCM/NoPadding", provider); + } + + c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES")); + + byte[] encryptedKey = c.doFinal(encodedKey); + + AlgorithmParameters algParams = c.getParameters(); + + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algParams.getEncoded()))); + + EncryptedPrivateKeyInfo keyInfo = new EncryptedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey); + + EncryptedPrivateKeyData keySeq = createPrivateKeySequence(keyInfo, chain); + + entries.put(alias, new ObjectData(PRIVATE_KEY, alias, creationDate, lastEditDate, keySeq.getEncoded(), null)); + } + catch (Exception e) + { + throw new ExtKeyStoreException("BCFKS KeyStore exception storing private key: " + e.toString(), e); + } + } + else if (key instanceof SecretKey) + { + if (chain != null) + { + throw new KeyStoreException("BCFKS KeyStore cannot store certificate chain with secret key."); + } + + try + { + byte[] encodedKey = key.getEncoded(); + + KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(256 / 8); + byte[] keyBytes = generateKey(pbkdAlgId, "SECRET_KEY_ENCRYPTION", ((password != null) ? password : new char[0])); + + Cipher c; + if (provider == null) + { + c = Cipher.getInstance("AES/CCM/NoPadding"); + } + else + { + c = Cipher.getInstance("AES/CCM/NoPadding", provider); + } + + c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES")); + + + String keyAlg = Strings.toUpperCase(key.getAlgorithm()); + byte[] encryptedKey; + + if (keyAlg.indexOf("AES") > -1) + { + encryptedKey = c.doFinal(new SecretKeyData(NISTObjectIdentifiers.aes, encodedKey).getEncoded()); + } + else + { + ASN1ObjectIdentifier algOid = (ASN1ObjectIdentifier)oidMap.get(keyAlg); + if (algOid != null) + { + encryptedKey = c.doFinal(new SecretKeyData(algOid, encodedKey).getEncoded()); + } + else + { + throw new KeyStoreException("BCFKS KeyStore cannot recognize secret key (" + keyAlg + ") for storage."); + } + } + + + AlgorithmParameters algParams = c.getParameters(); + + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algParams.getEncoded()))); + + EncryptedSecretKeyData keyData = new EncryptedSecretKeyData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey); + + entries.put(alias, new ObjectData(SECRET_KEY, alias, creationDate, lastEditDate, keyData.getEncoded(), null)); + } + catch (Exception e) + { + throw new ExtKeyStoreException("BCFKS KeyStore exception storing private key: " + e.toString(), e); + } + } + else + { + throw new KeyStoreException("BCFKS KeyStore unable to recognize key."); + } + + lastModifiedDate = lastEditDate; + } + + private SecureRandom getDefaultSecureRandom() + { + return new SecureRandom(); + } + + private EncryptedPrivateKeyData createPrivateKeySequence(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo, Certificate[] chain) + throws CertificateEncodingException + { + org.bouncycastle.asn1.x509.Certificate[] certChain = new org.bouncycastle.asn1.x509.Certificate[chain.length]; + for (int i = 0; i != chain.length; i++) + { + certChain[i] = org.bouncycastle.asn1.x509.Certificate.getInstance(chain[i].getEncoded()); + } + + return new EncryptedPrivateKeyData(encryptedPrivateKeyInfo, certChain); + } + + public void engineSetKeyEntry(String alias, byte[] keyBytes, Certificate[] chain) + throws KeyStoreException + { + Date creationDate = new Date(); + Date lastEditDate = creationDate; + + ObjectData entry = (ObjectData)entries.get(alias); + if (entry != null) + { + creationDate = extractCreationDate(entry, creationDate); + } + + if (chain != null) + { + EncryptedPrivateKeyInfo encInfo; + + try + { + encInfo = EncryptedPrivateKeyInfo.getInstance(keyBytes); + } + catch (Exception e) + { + throw new ExtKeyStoreException("BCFKS KeyStore private key encoding must be an EncryptedPrivateKeyInfo.", e); + } + + try + { + privateKeyCache.remove(alias); + entries.put(alias, new ObjectData(PROTECTED_PRIVATE_KEY, alias, creationDate, lastEditDate, createPrivateKeySequence(encInfo, chain).getEncoded(), null)); + } + catch (Exception e) + { + throw new ExtKeyStoreException("BCFKS KeyStore exception storing protected private key: " + e.toString(), e); + } + } + else + { + try + { + entries.put(alias, new ObjectData(PROTECTED_SECRET_KEY, alias, creationDate, lastEditDate, keyBytes, null)); + } + catch (Exception e) + { + throw new ExtKeyStoreException("BCFKS KeyStore exception storing protected private key: " + e.toString(), e); + } + } + + lastModifiedDate = lastEditDate; + } + + public void engineSetCertificateEntry(String alias, Certificate certificate) + throws KeyStoreException + { + ObjectData entry = (ObjectData)entries.get(alias); + Date creationDate = new Date(); + Date lastEditDate = creationDate; + + if (entry != null) + { + if (!entry.getType().equals(CERTIFICATE)) + { + throw new KeyStoreException("BCFKS KeyStore already has a key entry with alias " + alias); + } + + creationDate = extractCreationDate(entry, creationDate); + } + + try + { + entries.put(alias, new ObjectData(CERTIFICATE, alias, creationDate, lastEditDate, certificate.getEncoded(), null)); + } + catch (CertificateEncodingException e) + { + throw new ExtKeyStoreException("BCFKS KeyStore unable to handle certificate: " + e.getMessage(), e); + } + + lastModifiedDate = lastEditDate; + } + + private Date extractCreationDate(ObjectData entry, Date creationDate) + { + try + { + creationDate = entry.getCreationDate().getDate(); + } + catch (ParseException e) + { + // this should never happen, if it does we'll leave creation date unmodified and hope for the best. + } + return creationDate; + } + + public void engineDeleteEntry(String alias) + throws KeyStoreException + { + ObjectData entry = (ObjectData)entries.get(alias); + + if (entry == null) + { + return; + } + + privateKeyCache.remove(alias); + entries.remove(alias); + + lastModifiedDate = new Date(); + } + + public Enumeration engineAliases() + { + final Iterator it = new HashSet(entries.keySet()).iterator(); + + return new Enumeration() + { + public boolean hasMoreElements() + { + return it.hasNext(); + } + + public Object nextElement() + { + return it.next(); + } + }; + } + + public boolean engineContainsAlias(String alias) + { + if (alias == null) + { + throw new NullPointerException("alias value is null"); + } + + return entries.containsKey(alias); + } + + public int engineSize() + { + return entries.size(); + } + + public boolean engineIsKeyEntry(String alias) + { + ObjectData ent = (ObjectData)entries.get(alias); + + if (ent != null) + { + BigInteger entryType = ent.getType(); + return entryType.equals(PRIVATE_KEY) || entryType.equals(SECRET_KEY) + || entryType.equals(PROTECTED_PRIVATE_KEY) || entryType.equals(PROTECTED_SECRET_KEY); + } + + return false; + } + + public boolean engineIsCertificateEntry(String alias) + { + ObjectData ent = (ObjectData)entries.get(alias); + + if (ent != null) + { + return ent.getType().equals(CERTIFICATE); + } + + return false; + } + + public String engineGetCertificateAlias(Certificate certificate) + { + byte[] encodedCert; + try + { + encodedCert = certificate.getEncoded(); + } + catch (CertificateEncodingException e) + { + return null; + } + + for (Iterator it = entries.keySet().iterator(); it.hasNext(); ) + { + String alias = (String)it.next(); + ObjectData ent = (ObjectData)entries.get(alias); + + if (ent.getType().equals(CERTIFICATE)) + { + if (Arrays.areEqual(ent.getData(), encodedCert)) + { + return alias; + } + } + else if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY)) + { + try + { + EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData()); + if (Arrays.areEqual(encPrivData.getCertificateChain()[0].toASN1Primitive().getEncoded(), encodedCert)) + { + return alias; + } + } + catch (IOException e) + { + // ignore - this should never happen + } + } + } + + return null; + } + + private byte[] generateKey(KeyDerivationFunc pbkdAlgorithm, String purpose, char[] password) + throws IOException + { + byte[] encPassword = PBEParametersGenerator.PKCS12PasswordToBytes(password); + byte[] differentiator = PBEParametersGenerator.PKCS12PasswordToBytes(purpose.toCharArray()); + + int keySizeInBytes; + PKCS5S2ParametersGenerator pGen = new PKCS5S2ParametersGenerator(new SHA512Digest()); + + if (pbkdAlgorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_PBKDF2)) + { + PBKDF2Params pbkdf2Params = PBKDF2Params.getInstance(pbkdAlgorithm.getParameters()); + + if (pbkdf2Params.getPrf().getAlgorithm().equals(PKCSObjectIdentifiers.id_hmacWithSHA512)) + { + + pGen.init(Arrays.concatenate(encPassword, differentiator), pbkdf2Params.getSalt(), pbkdf2Params.getIterationCount().intValue()); + + keySizeInBytes = pbkdf2Params.getKeyLength().intValue(); + } + else + { + throw new IOException("BCFKS KeyStore: unrecognized MAC PBKD PRF."); + } + } + else + { + throw new IOException("BCFKS KeyStore: unrecognized MAC PBKD."); + } + + return ((KeyParameter)pGen.generateDerivedParameters(keySizeInBytes * 8)).getKey(); + } + + private void verifyMac(byte[] content, PbkdMacIntegrityCheck integrityCheck, char[] password) + throws NoSuchAlgorithmException, IOException + { + byte[] check = calculateMac(content, integrityCheck.getMacAlgorithm(), integrityCheck.getPbkdAlgorithm(), password); + + if (!Arrays.constantTimeAreEqual(check, integrityCheck.getMac())) + { + throw new IOException("BCFKS KeyStore corrupted: MAC calculation failed."); + } + } + + private byte[] calculateMac(byte[] content, AlgorithmIdentifier algorithm, KeyDerivationFunc pbkdAlgorithm, char[] password) + throws NoSuchAlgorithmException, IOException + { + String algorithmId = algorithm.getAlgorithm().getId(); + + Mac mac; + if (provider != null) + { + mac = Mac.getInstance(algorithmId, provider); + } + else + { + mac = Mac.getInstance(algorithmId); + } + + try + { + mac.init(new SecretKeySpec(generateKey(pbkdAlgorithm, "INTEGRITY_CHECK", ((password != null) ? password : new char[0])), algorithmId)); + } + catch (InvalidKeyException e) + { + throw new IOException("Cannot set up MAC calculation: " + e.getMessage()); + } + + return mac.doFinal(content); + } + + public void engineStore(OutputStream outputStream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException + { + ObjectData[] dataArray = (ObjectData[])entries.values().toArray(new ObjectData[entries.size()]); + + KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(256 / 8); + byte[] keyBytes = generateKey(pbkdAlgId, "STORE_ENCRYPTION", ((password != null) ? password : new char[0])); + + ObjectStoreData storeData = new ObjectStoreData(hmacAlgorithm, creationDate, lastModifiedDate, new ObjectDataSequence(dataArray), null); + EncryptedObjectStoreData encStoreData; + + try + { + Cipher c; + if (provider == null) + { + c = Cipher.getInstance("AES/CCM/NoPadding"); + } + else + { + c = Cipher.getInstance("AES/CCM/NoPadding", provider); + } + + c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES")); + + byte[] encOut = c.doFinal(storeData.getEncoded()); + + AlgorithmParameters algorithmParameters = c.getParameters(); + + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algorithmParameters.getEncoded()))); + + encStoreData = new EncryptedObjectStoreData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encOut); + } + catch (NoSuchPaddingException e) + { + throw new NoSuchAlgorithmException(e.toString()); + } + catch (BadPaddingException e) + { + throw new IOException(e.toString()); + } + catch (IllegalBlockSizeException e) + { + throw new IOException(e.toString()); + } + catch (InvalidKeyException e) + { + throw new IOException(e.toString()); + } + + // update the salt + PBKDF2Params pbkdf2Params = PBKDF2Params.getInstance(hmacPkbdAlgorithm.getParameters()); + + byte[] pbkdSalt = new byte[pbkdf2Params.getSalt().length]; + getDefaultSecureRandom().nextBytes(pbkdSalt); + + hmacPkbdAlgorithm = new KeyDerivationFunc(hmacPkbdAlgorithm.getAlgorithm(), new PBKDF2Params(pbkdSalt, pbkdf2Params.getIterationCount().intValue(), pbkdf2Params.getKeyLength().intValue(), pbkdf2Params.getPrf())); + + byte[] mac = calculateMac(encStoreData.getEncoded(), hmacAlgorithm, hmacPkbdAlgorithm, password); + + ObjectStore store = new ObjectStore(encStoreData, new ObjectStoreIntegrityCheck(new PbkdMacIntegrityCheck(hmacAlgorithm, hmacPkbdAlgorithm, mac))); + + outputStream.write(store.getEncoded()); + + outputStream.flush(); + } + + public void engineLoad(InputStream inputStream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException + { + // reset any current values + entries.clear(); + privateKeyCache.clear(); + + lastModifiedDate = creationDate = null; + hmacAlgorithm = null; + + if (inputStream == null) + { + // initialise defaults + lastModifiedDate = creationDate = new Date(); + + hmacAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE); + hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(512 / 8); + + return; + } + + ASN1InputStream aIn = new ASN1InputStream(inputStream); + + ObjectStore store = ObjectStore.getInstance(aIn.readObject()); + + ObjectStoreIntegrityCheck integrityCheck = store.getIntegrityCheck(); + if (integrityCheck.getType() == ObjectStoreIntegrityCheck.PBKD_MAC_CHECK) + { + PbkdMacIntegrityCheck pbkdMacIntegrityCheck = PbkdMacIntegrityCheck.getInstance(integrityCheck.getIntegrityCheck()); + + hmacAlgorithm = pbkdMacIntegrityCheck.getMacAlgorithm(); + hmacPkbdAlgorithm = pbkdMacIntegrityCheck.getPbkdAlgorithm(); + + verifyMac(store.getStoreData().toASN1Primitive().getEncoded(), pbkdMacIntegrityCheck, password); + } + else + { + throw new IOException("BCFKS KeyStore unable to recognize integrity check."); + } + + ASN1Encodable sData = store.getStoreData(); + + ObjectStoreData storeData; + if (sData instanceof EncryptedObjectStoreData) + { + EncryptedObjectStoreData encryptedStoreData = (EncryptedObjectStoreData)sData; + AlgorithmIdentifier protectAlgId = encryptedStoreData.getEncryptionAlgorithm(); + + storeData = ObjectStoreData.getInstance(decryptData("STORE_ENCRYPTION", protectAlgId, password, encryptedStoreData.getEncryptedContent().getOctets())); + } + else + { + storeData = ObjectStoreData.getInstance(sData); + } + + try + { + creationDate = storeData.getCreationDate().getDate(); + lastModifiedDate = storeData.getLastModifiedDate().getDate(); + } + catch (ParseException e) + { + throw new IOException("BCFKS KeyStore unable to parse store data information."); + } + + if (!storeData.getIntegrityAlgorithm().equals(hmacAlgorithm)) + { + throw new IOException("BCFKS KeyStore storeData integrity algorithm does not match store integrity algorithm."); + } + + for (Iterator it = storeData.getObjectDataSequence().iterator(); it.hasNext(); ) + { + ObjectData objData = ObjectData.getInstance(it.next()); + + entries.put(objData.getIdentifier(), objData); + } + } + + private byte[] decryptData(String purpose, AlgorithmIdentifier protectAlgId, char[] password, byte[] encryptedData) + throws IOException + { + if (!protectAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_PBES2)) + { + throw new IOException("BCFKS KeyStore cannot recognize protection algorithm."); + } + + PBES2Parameters pbes2Parameters = PBES2Parameters.getInstance(protectAlgId.getParameters()); + EncryptionScheme algId = pbes2Parameters.getEncryptionScheme(); + + if (!algId.getAlgorithm().equals(NISTObjectIdentifiers.id_aes256_CCM)) + { + throw new IOException("BCFKS KeyStore cannot recognize protection encryption algorithm."); + } + + try + { + CCMParameters ccmParameters = CCMParameters.getInstance(algId.getParameters()); + Cipher c; + AlgorithmParameters algParams; + if (provider == null) + { + c = Cipher.getInstance("AES/CCM/NoPadding"); + algParams = AlgorithmParameters.getInstance("CCM"); + } + else + { + c = Cipher.getInstance("AES/CCM/NoPadding", provider); + algParams = AlgorithmParameters.getInstance("CCM", provider.getName()); + } + + algParams.init(ccmParameters.getEncoded()); + + byte[] keyBytes = generateKey(pbes2Parameters.getKeyDerivationFunc(), purpose, ((password != null) ? password : new char[0])); + + c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), algParams); + + byte[] rv = c.doFinal(encryptedData); + return rv; + } + catch (Exception e) + { + throw new IOException(e.toString()); + } + } + + private KeyDerivationFunc generatePkbdAlgorithmIdentifier(int keySizeInBytes) + { + byte[] pbkdSalt = new byte[512 / 8]; + getDefaultSecureRandom().nextBytes(pbkdSalt); + return new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(pbkdSalt, 1024, keySizeInBytes, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE))); + } + + public static class Std + extends BcFKSKeyStoreSpi + { + public Std() + { + super(new BouncyCastleProvider()); + } + } + + public static class Def + extends BcFKSKeyStoreSpi + { + public Def() + { + super(null); + } + } + + private static class ExtKeyStoreException + extends KeyStoreException + { + private final Throwable cause; + + ExtKeyStoreException(String msg, Throwable cause) + { + super(msg); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } + } +} diff -Nru bouncycastle-1.55/prov/src/main/jdk1.3/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java bouncycastle-1.56/prov/src/main/jdk1.3/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java --- bouncycastle-1.55/prov/src/main/jdk1.3/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java 2015-02-16 23:18:19.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.3/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java 2016-12-20 01:53:07.000000000 +0000 @@ -8,6 +8,7 @@ import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Provider; +import java.security.SecureRandom; import java.security.Signature; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; @@ -103,4 +104,10 @@ { return CertificateFactory.getInstance(algorithm, provider.getName()); } + + public SecureRandom createSecureRandom(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return SecureRandom.getInstance(algorithm, provider.getName()); + } } diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java 2015-08-17 06:50:36.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java 2016-08-21 01:20:53.000000000 +0000 @@ -8,6 +8,7 @@ import java.util.Enumeration; import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; @@ -220,61 +221,35 @@ */ public byte[] getEncoded() { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - DEROutputStream dOut = new DEROutputStream(bOut); - X962Parameters params = null; + X962Parameters params = ECUtils.getDomainParametersFromName(ecSpec, withCompression); - if (ecSpec instanceof ECNamedCurveParameterSpec) + int orderBitLength; + if (ecSpec == null) { - ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName()); - - params = new X962Parameters(curveOid); - } - else if (ecSpec == null) - { - params = new X962Parameters(DERNull.INSTANCE); + orderBitLength = ECUtil.getOrderBitLength(configuration, null, this.getD()); } else { - ECParameterSpec p = (ECParameterSpec)ecSpec; - - ECPoint pG = p.getG().normalize(); - ECPoint g = pG.getCurve().createPoint(pG.getAffineXCoord().toBigInteger(), pG.getAffineYCoord().toBigInteger()); - - X9ECParameters ecP = new X9ECParameters( - p.getCurve(), - g, - p.getN(), - p.getH(), - p.getSeed()); - - params = new X962Parameters(ecP); + orderBitLength = ECUtil.getOrderBitLength(configuration, ecSpec.getN(), this.getD()); } - PrivateKeyInfo info; - ECPrivateKeyStructure keyStructure; + PrivateKeyInfo info; + org.bouncycastle.asn1.sec.ECPrivateKey keyStructure; if (publicKey != null) { - keyStructure = new ECPrivateKeyStructure(this.getD(), publicKey, params); + keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getD(), publicKey, params); } else { - keyStructure = new ECPrivateKeyStructure(this.getD(), params); + keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getD(), params); } try { - if (algorithm.equals("ECGOST3410")) - { - info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), keyStructure); - } - else - { - info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure); - } + info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure); - return KeyUtil.getEncodedPrivateKeyInfo(info); + return info.getEncoded(ASN1Encoding.DER); } catch (IOException e) { diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java 2015-08-17 06:50:36.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java 2016-08-21 01:37:02.000000000 +0000 @@ -36,20 +36,21 @@ public class BCECPublicKey implements ECPublicKey, ECPointEncoder { + static final long serialVersionUID = 2422789860422731812L; + private String algorithm = "EC"; private boolean withCompression; - private transient org.bouncycastle.math.ec.ECPoint q; + private transient ECPublicKeyParameters ecPublicKey; private transient ECParameterSpec ecSpec; private transient ProviderConfiguration configuration; public BCECPublicKey( String algorithm, - BCECPublicKey key - ) + BCECPublicKey key) { this.algorithm = algorithm; - this.q = key.q; + this.ecPublicKey = key.ecPublicKey; this.ecSpec = key.ecSpec; this.withCompression = key.withCompression; this.configuration = key.configuration; @@ -61,23 +62,23 @@ ProviderConfiguration configuration) { this.algorithm = algorithm; - this.q = spec.getQ(); - this.configuration = configuration; if (spec.getParams() != null) { this.ecSpec = spec.getParams(); + this.ecPublicKey = new ECPublicKeyParameters(spec.getQ(), ECUtil.getDomainParameters(configuration, spec.getParams())); + } else { - if (q.getCurve() == null) - { - org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - - q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false); - } this.ecSpec = null; + + org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa(); + + this.ecPublicKey = new ECPublicKeyParameters(s.getCurve().createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger()), ECUtil.getDomainParameters(configuration, (ECParameterSpec)null)); } + + this.configuration = configuration; } public BCECPublicKey( @@ -89,7 +90,7 @@ ECDomainParameters dp = params.getParameters(); this.algorithm = algorithm; - this.q = params.getQ(); + this.ecPublicKey = params; this.configuration = configuration; if (spec == null) @@ -113,7 +114,7 @@ ProviderConfiguration configuration) { this.algorithm = algorithm; - this.q = params.getQ(); + this.ecPublicKey = params; this.ecSpec = null; this.configuration = configuration; } @@ -122,7 +123,7 @@ ECPublicKey key, ProviderConfiguration configuration) { - this.q = key.getQ(); + this.ecPublicKey = new ECPublicKeyParameters(key.getQ(), ECUtil.getDomainParameters(configuration, key.getParameters())); this.algorithm = key.getAlgorithm(); this.ecSpec = key.getParameters(); this.configuration = configuration; @@ -135,7 +136,7 @@ ProviderConfiguration configuration) { this.algorithm = algorithm; - this.q = q; + this.ecPublicKey = new ECPublicKeyParameters(q, ECUtil.getDomainParameters(configuration, ecSpec)); this.ecSpec = ecSpec; this.configuration = configuration; } @@ -222,7 +223,7 @@ X9ECPoint derQ = new X9ECPoint(curve, key); - this.q = derQ.getPoint(); + this.ecPublicKey = new ECPublicKeyParameters(derQ.getPoint(), ECUtil.getDomainParameters(configuration, params)); } public String getAlgorithm() @@ -237,41 +238,10 @@ public byte[] getEncoded() { - SubjectPublicKeyInfo info; - - X962Parameters params = null; - if (ecSpec instanceof ECNamedCurveParameterSpec) - { - ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName()); - - if (curveOid == null) - { - curveOid = new ASN1ObjectIdentifier(((ECNamedCurveParameterSpec)ecSpec).getName()); - } - params = new X962Parameters(curveOid); - } - else if (ecSpec == null) - { - params = new X962Parameters(DERNull.INSTANCE); - } - else - { - ECParameterSpec p = (ECParameterSpec)ecSpec; + X962Parameters params = ECUtils.getDomainParametersFromName(ecSpec, withCompression); + ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(ecPublicKey.getQ(), withCompression).toASN1Primitive()); - ECCurve curve = p.getG().getCurve(); - ECPoint generator = curve.createPoint(p.getG().getX().toBigInteger(), p.getG().getY().toBigInteger(), withCompression); - - X9ECParameters ecP = new X9ECParameters( - p.getCurve(), generator, p.getN(), p.getH(), p.getSeed()); - - params = new X962Parameters(ecP); - } - - ECCurve curve = this.engineGetQ().getCurve(); - ECPoint point = curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression); - ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(point)); - - info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); return KeyUtil.getEncodedSubjectPublicKeyInfo(info); } @@ -290,22 +260,22 @@ { if (ecSpec == null) { - if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp) + if (ecPublicKey.getQ() instanceof org.bouncycastle.math.ec.ECPoint.Fp) { - return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY()); + return new org.bouncycastle.math.ec.ECPoint.Fp(null, ecPublicKey.getQ().getX(), ecPublicKey.getQ().getY()); } else { - return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY()); + return new org.bouncycastle.math.ec.ECPoint.F2m(null, ecPublicKey.getQ().getX(), ecPublicKey.getQ().getY()); } } - return q; + return ecPublicKey.getQ(); } - public org.bouncycastle.math.ec.ECPoint engineGetQ() + ECPublicKeyParameters engineGetKeyParameters() { - return q; + return ecPublicKey; } public String toString() @@ -318,7 +288,6 @@ buf.append(" Y: ").append(this.getQ().getY().toBigInteger().toString(16)).append(nl); return buf.toString(); - } public void setPointFormat(String style) diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java 2016-08-21 00:16:46.000000000 +0000 @@ -0,0 +1,60 @@ +package org.bouncycastle.jcajce.provider.asymmetric.ec; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.PublicKey; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.x9.X962Parameters; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +class ECUtils +{ + static AsymmetricKeyParameter generatePublicKeyParameter( + PublicKey key) + throws InvalidKeyException + { + return (key instanceof BCECPublicKey) ? ((BCECPublicKey)key).engineGetKeyParameters() : ECUtil.generatePublicKeyParameter(key); + } + + static X962Parameters getDomainParametersFromName(ECParameterSpec ecSpec, boolean withCompression) + { + X962Parameters params; + + if (ecSpec instanceof ECNamedCurveParameterSpec) + { + ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName()); + + if (curveOid == null) + { + curveOid = new ASN1ObjectIdentifier(((ECNamedCurveParameterSpec)ecSpec).getName()); + } + params = new X962Parameters(curveOid); + } + else if (ecSpec == null) + { + params = new X962Parameters(DERNull.INSTANCE); + } + else + { + ECParameterSpec p = (ECParameterSpec)ecSpec; + + ECCurve curve = p.getG().getCurve(); + ECPoint generator = curve.createPoint(p.getG().getX().toBigInteger(), p.getG().getY().toBigInteger(), withCompression); + + X9ECParameters ecP = new X9ECParameters( + p.getCurve(), generator, p.getN(), p.getH(), p.getSeed()); + + params = new X962Parameters(ecP); + } + + return params; + } +} diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java 2012-01-06 02:17:01.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java 2016-08-21 03:21:38.000000000 +0000 @@ -106,9 +106,16 @@ KeySpec keySpec) throws InvalidKeySpecException { - if (keySpec instanceof ECPublicKeySpec) + try { - return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration); + if (keySpec instanceof ECPublicKeySpec) + { + return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration); + } + } + catch (Exception e) + { + throw new InvalidKeySpecException("invalid KeySpec: " + e.getMessage()); } return super.engineGeneratePublic(keySpec); diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java 2016-08-13 01:26:28.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java 2016-08-21 00:38:28.000000000 +0000 @@ -46,34 +46,7 @@ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { - CipherParameters param; - - if (publicKey instanceof ECPublicKey) - { - param = ECUtil.generatePublicKeyParameter(publicKey); - } - else - { - try - { - byte[] bytes = publicKey.getEncoded(); - - publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes)); - - if (publicKey instanceof ECPublicKey) - { - param = ECUtil.generatePublicKeyParameter(publicKey); - } - else - { - throw new InvalidKeyException("can't recognise key type in ECDSA based signer"); - } - } - catch (Exception e) - { - throw new InvalidKeyException("can't recognise key type in ECDSA based signer"); - } - } + CipherParameters param = ECUtils.generatePublicKeyParameter(publicKey); digest.reset(); diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java 2015-08-17 06:54:46.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java 2016-08-21 23:08:46.000000000 +0000 @@ -28,6 +28,7 @@ import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; +import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import org.bouncycastle.jce.ECGOST3410NamedCurveTable; import org.bouncycastle.jce.interfaces.ECPointEncoder; import org.bouncycastle.jce.interfaces.ECPublicKey; @@ -45,7 +46,7 @@ private String algorithm = "ECGOST3410"; private boolean withCompression; - private transient org.bouncycastle.math.ec.ECPoint q; + private transient ECPublicKeyParameters ecPublicKey; private transient ECParameterSpec ecSpec; private transient GOST3410PublicKeyAlgParameters gostParams; @@ -54,30 +55,29 @@ BCECGOST3410PublicKey key) { this.algorithm = algorithm; - this.q = key.q; + this.ecPublicKey = key.ecPublicKey; this.ecSpec = key.ecSpec; this.withCompression = key.withCompression; this.gostParams = key.gostParams; } public BCECGOST3410PublicKey( - ECPublicKeySpec spec) + ECPublicKeySpec spec, + ProviderConfiguration configuration) { - this.q = spec.getQ(); - if (spec.getParams() != null) { this.ecSpec = spec.getParams(); + this.ecPublicKey = new ECPublicKeyParameters(spec.getQ(), ECUtil.getDomainParameters(configuration, spec.getParams())); + } else { - if (q.getCurve() == null) - { - org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - - q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false); - } this.ecSpec = null; + + org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa(); + + this.ecPublicKey = new ECPublicKeyParameters(s.getCurve().createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger()), ECUtil.getDomainParameters(configuration, (ECParameterSpec)null)); } } @@ -89,7 +89,7 @@ ECDomainParameters dp = params.getParameters(); this.algorithm = algorithm; - this.q = params.getQ(); + this.ecPublicKey = params; if (spec == null) { @@ -111,14 +111,14 @@ ECPublicKeyParameters params) { this.algorithm = algorithm; - this.q = params.getQ(); + this.ecPublicKey = params; this.ecSpec = null; } BCECGOST3410PublicKey( ECPublicKey key) { - this.q = key.getQ(); + this.ecPublicKey = new ECPublicKeyParameters(key.getQ(), ECUtil.getDomainParameters(BouncyCastleProvider.CONFIGURATION, key.getParameters())); this.algorithm = key.getAlgorithm(); this.ecSpec = key.getParameters(); } @@ -129,7 +129,7 @@ ECParameterSpec ecSpec) { this.algorithm = algorithm; - this.q = q; + this.ecPublicKey = new ECPublicKeyParameters(q, ECUtil.getDomainParameters(BouncyCastleProvider.CONFIGURATION, ecSpec)); this.ecSpec = ecSpec; } @@ -176,7 +176,9 @@ ecSpec = spec; - this.q = spec.getCurve().createPoint(new BigInteger(1, x), new BigInteger(1, y), false); + ECPoint q = spec.getCurve().createPoint(new BigInteger(1, x), new BigInteger(1, y), false); + + this.ecPublicKey = new ECPublicKeyParameters(q, ECUtil.getDomainParameters(BouncyCastleProvider.CONFIGURATION, ecSpec)); } else { @@ -241,7 +243,9 @@ X9ECPoint derQ = new X9ECPoint(curve, key); - this.q = derQ.getPoint(); + ECPoint q = derQ.getPoint(); + + this.ecPublicKey = new ECPublicKeyParameters(q, ECUtil.getDomainParameters(BouncyCastleProvider.CONFIGURATION, ecSpec)); } } @@ -289,8 +293,8 @@ ECPoint point = qq.getCurve().createPoint(qq.getX().toBigInteger(), qq.getY().toBigInteger(), false); ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(point)); - BigInteger bX = this.q.getX().toBigInteger(); - BigInteger bY = this.q.getY().toBigInteger(); + BigInteger bX = getQ().getX().toBigInteger(); + BigInteger bY = getQ().getY().toBigInteger(); byte[] encKey = new byte[64]; byte[] val = bX.toByteArray(); @@ -346,7 +350,7 @@ params = new X962Parameters(ecP); } - ECCurve curve = this.engineGetQ().getCurve(); + ECCurve curve = this.ecPublicKey.getParameters().getCurve(); ECPoint point = curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression); ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(point)); @@ -368,6 +372,8 @@ public org.bouncycastle.math.ec.ECPoint getQ() { + ECPoint q = ecPublicKey.getQ(); + if (ecSpec == null) { if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp) @@ -383,9 +389,9 @@ return q; } - public org.bouncycastle.math.ec.ECPoint engineGetQ() + ECPublicKeyParameters engineGetKeyParameters() { - return q; + return ecPublicKey; } public String toString() diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java 2012-01-06 01:41:52.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java 2016-08-21 23:04:07.000000000 +0000 @@ -90,7 +90,7 @@ { if (keySpec instanceof ECPublicKeySpec) { - return new BCECGOST3410PublicKey((ECPublicKeySpec)keySpec); + return new BCECGOST3410PublicKey((ECPublicKeySpec)keySpec, BouncyCastleProvider.CONFIGURATION); } return super.engineGeneratePublic(keySpec); diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java 2015-01-31 23:34:17.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java 2016-08-21 23:07:33.000000000 +0000 @@ -16,6 +16,7 @@ import org.bouncycastle.crypto.digests.GOST3411Digest; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.signers.ECGOST3410Signer; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jce.interfaces.ECKey; import org.bouncycastle.jce.interfaces.ECPublicKey; @@ -45,7 +46,7 @@ if (publicKey instanceof ECPublicKey) { - param = ECUtil.generatePublicKeyParameter(publicKey); + param = generatePublicKeyParameter(publicKey); } else if (publicKey instanceof GOST3410Key) { @@ -209,4 +210,12 @@ { throw new UnsupportedOperationException("engineSetParameter unsupported"); } + + + static AsymmetricKeyParameter generatePublicKeyParameter( + PublicKey key) + throws InvalidKeyException + { + return (key instanceof BCECGOST3410PublicKey) ? ((BCECGOST3410PublicKey)key).engineGetKeyParameters() : ECUtil.generatePublicKeyParameter(key); + } } diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java 2015-02-14 03:41:53.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java 2016-08-23 01:21:50.000000000 +0000 @@ -241,14 +241,8 @@ throws IllegalBlockSizeException, BadPaddingException { cipher.processBytes(input, inputOffset, inputLen); - try - { - return cipher.doFinal(); - } - catch (InvalidCipherTextException e) - { - throw new BadPaddingException(e.getMessage()); - } + + return getOutput(); } protected int engineDoFinal( @@ -256,21 +250,12 @@ int inputOffset, int inputLen, byte[] output, - int outputOffset) + int outputOffset) throws IllegalBlockSizeException, BadPaddingException { - byte[] out; - cipher.processBytes(input, inputOffset, inputLen); - try - { - out = cipher.doFinal(); - } - catch (InvalidCipherTextException e) - { - throw new BadPaddingException(e.getMessage()); - } + byte[] out = getOutput(); for (int i = 0; i != out.length; i++) { @@ -280,6 +265,25 @@ return out.length; } + private byte[] getOutput() + throws BadPaddingException + { + try + { + return cipher.doFinal(); + } + catch (final InvalidCipherTextException e) + { + throw new BadPaddingException("unable to decrypt block") + { + public synchronized Throwable getCause() + { + return e; + } + }; + } + } + /** * classes that inherit from us. */ diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java 2015-02-14 03:40:01.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java 2016-08-23 01:21:50.000000000 +0000 @@ -364,10 +364,10 @@ } protected byte[] engineDoFinal( - byte[] input, - int inputOffset, - int inputLen) - throws IllegalBlockSizeException, BadPaddingException + byte[] input, + int inputOffset, + int inputLen) + throws IllegalBlockSizeException, BadPaddingException { if (input != null) { @@ -389,18 +389,7 @@ } } - try - { - byte[] bytes = bOut.toByteArray(); - - bOut.reset(); - - return cipher.processBlock(bytes, 0, bytes.length); - } - catch (InvalidCipherTextException e) - { - throw new BadPaddingException(e.getMessage()); - } + return getOutput(); } protected int engineDoFinal( @@ -408,7 +397,7 @@ int inputOffset, int inputLen, byte[] output, - int outputOffset) + int outputOffset) throws IllegalBlockSizeException, BadPaddingException { if (input != null) @@ -431,26 +420,39 @@ } } - byte[] out; + byte[] out = getOutput(); + for (int i = 0; i != out.length; i++) + { + output[outputOffset + i] = out[i]; + } + + return out.length; + } + + private byte[] getOutput() + throws BadPaddingException + { try { byte[] bytes = bOut.toByteArray(); - bOut.reset(); - out = cipher.processBlock(bytes, 0, bytes.length); + return cipher.processBlock(bytes, 0, bytes.length); } - catch (InvalidCipherTextException e) + catch (final InvalidCipherTextException e) { - throw new BadPaddingException(e.getMessage()); + throw new BadPaddingException("unable to decrypt block") + { + public synchronized Throwable getCause() + { + return e; + } + }; } - - for (int i = 0; i != out.length; i++) + finally { - output[outputOffset + i] = out[i]; + bOut.reset(); } - - return out.length; } /** diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java 2013-04-14 09:12:04.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java 2016-08-21 01:15:54.000000000 +0000 @@ -1,5 +1,6 @@ package org.bouncycastle.jcajce.provider.asymmetric.util; +import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.PrivateKey; import java.security.PublicKey; @@ -7,19 +8,24 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; import org.bouncycastle.asn1.nist.NISTNamedCurves; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.sec.SECNamedCurves; import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; import org.bouncycastle.asn1.x9.X962NamedCurves; import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECNamedDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.jce.interfaces.ECPrivateKey; import org.bouncycastle.jce.interfaces.ECPublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; /** * utility class for converting jce/jca ECDSA, ECDH, and ECDHC @@ -97,28 +103,116 @@ return res; } + public static ECDomainParameters getDomainParameters( + ProviderConfiguration configuration, + org.bouncycastle.jce.spec.ECParameterSpec params) + { + ECDomainParameters domainParameters; + + if (params instanceof ECNamedCurveParameterSpec) + { + ECNamedCurveParameterSpec nParams = (ECNamedCurveParameterSpec)params; + ASN1ObjectIdentifier nameOid = ECUtil.getNamedCurveOid(nParams.getName()); + + domainParameters = new ECNamedDomainParameters(nameOid, nParams.getCurve(), nParams.getG(), nParams.getN(), nParams.getH(), nParams.getSeed()); + } + else if (params == null) + { + org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa(); + + domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed()); + } + else + { + domainParameters = new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH(), params.getSeed()); + } + + return domainParameters; + } + + public static ECDomainParameters getDomainParameters( + ProviderConfiguration configuration, + X962Parameters params) + { + ECDomainParameters domainParameters; + + if (params.isNamedCurve()) + { + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); + X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid); + + domainParameters = new ECNamedDomainParameters(oid, ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); + } + else if (params.isImplicitlyCA()) + { + org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa(); + + domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed()); + } + else + { + X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); + + domainParameters = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); + } + + return domainParameters; + } + + public static int getOrderBitLength(ProviderConfiguration configuration, BigInteger order, BigInteger privateValue) + { + if (order == null) // implicitly CA + { + ECParameterSpec implicitCA = configuration.getEcImplicitlyCa(); + + if (implicitCA == null) + { + return privateValue.bitLength(); // a guess but better than an exception! + } + + return implicitCA.getN().bitLength(); + } + else + { + return order.bitLength(); + } + } + public static AsymmetricKeyParameter generatePublicKeyParameter( PublicKey key) throws InvalidKeyException { - if (key instanceof ECPublicKey) + if (key instanceof ECPublicKey && ((ECPublicKey)key).getParameters() != null) { ECPublicKey k = (ECPublicKey)key; ECParameterSpec s = k.getParameters(); - if (s == null) + return new ECPublicKeyParameters( + k.getQ(), + new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); + } + else + { + // see if we can build a key from key.getEncoded() + try { - s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + byte[] bytes = key.getEncoded(); - return new ECPublicKeyParameters( - ((BCECPublicKey)k).engineGetQ(), - new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); + if (bytes == null) + { + throw new InvalidKeyException("no encoding for EC public key"); + } + + PublicKey publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes)); + + if (publicKey instanceof ECPublicKey) + { + return ECUtil.generatePublicKeyParameter(publicKey); + } } - else + catch (Exception e) { - return new ECPublicKeyParameters( - k.getQ(), - new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); + throw new InvalidKeyException("cannot identify EC public key: " + e.toString()); } } @@ -143,7 +237,31 @@ k.getD(), new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); } - + else + { + // see if we can build a key from key.getEncoded() + try + { + byte[] bytes = key.getEncoded(); + + if (bytes == null) + { + throw new InvalidKeyException("no encoding for EC private key"); + } + + PrivateKey privateKey = BouncyCastleProvider.getPrivateKey(PrivateKeyInfo.getInstance(bytes)); + + if (privateKey instanceof ECPrivateKey) + { + return ECUtil.generatePrivateKeyParameter(privateKey); + } + } + catch (Exception e) + { + throw new InvalidKeyException("cannot identify EC private key: " + e.toString()); + } + } + throw new InvalidKeyException("can't identify EC private key."); } diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/drbg/DRBG.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/drbg/DRBG.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/drbg/DRBG.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/drbg/DRBG.java 2016-12-16 23:42:25.000000000 +0000 @@ -0,0 +1,91 @@ +package org.bouncycastle.jcajce.provider.drbg; + +import java.security.SecureRandom; +import java.security.SecureRandomSpi; + +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.prng.SP800SecureRandomBuilder; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; +import org.bouncycastle.util.Strings; + +public class DRBG +{ + private static final String PREFIX = DRBG.class.getName(); + + public static class Default + extends SecureRandomSpi + { + private SecureRandom randomSource = new SecureRandom(); // needs to be done late, can't use static + private SecureRandom random = new SP800SecureRandomBuilder(randomSource, true) + .setPersonalizationString(generateDefaultPersonalizationString(randomSource)) + .buildHash(new SHA512Digest(), randomSource.generateSeed(32), true); + + protected void engineSetSeed(byte[] bytes) + { + random.setSeed(bytes); + } + + protected void engineNextBytes(byte[] bytes) + { + random.nextBytes(bytes); + } + + protected byte[] engineGenerateSeed(int numBytes) + { + return randomSource.generateSeed(numBytes); + } + } + + public static class NonceAndIV + extends SecureRandomSpi + { + private SecureRandom randomSource = new SecureRandom(); // needs to be done late, can't use static + private SecureRandom random = new SP800SecureRandomBuilder(randomSource, true) + .setPersonalizationString(generateNonceIVPersonalizationString(randomSource)) + .buildHash(new SHA512Digest(), randomSource.generateSeed(32), false); + + protected void engineSetSeed(byte[] bytes) + { + random.setSeed(bytes); + } + + protected void engineNextBytes(byte[] bytes) + { + random.nextBytes(bytes); + } + + protected byte[] engineGenerateSeed(int numBytes) + { + return randomSource.generateSeed(numBytes); + } + } + + public static class Mappings + extends AsymmetricAlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("SecureRandom.DEFAULT", PREFIX + "$Default"); + provider.addAlgorithm("SecureRandom.NONCEANDIV", PREFIX + "$NonceAndIV"); + } + } + + private static byte[] generateDefaultPersonalizationString(SecureRandom random) + { + return Arrays.concatenate(Strings.toByteArray("Default"), random.generateSeed(16), + Strings.toByteArray(Thread.currentThread().toString()), Pack.longToBigEndian(System.currentTimeMillis())); + } + + private static byte[] generateNonceIVPersonalizationString(SecureRandom random) + { + return Arrays.concatenate(Strings.toByteArray("Nonce"), random.generateSeed(16), + Strings.toByteArray(Thread.currentThread().toString()), Pack.longToLittleEndian(System.currentTimeMillis())); + } +} diff -Nru bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java --- bouncycastle-1.55/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java 2013-01-02 04:55:39.000000000 +0000 +++ bouncycastle-1.56/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java 2016-11-29 05:30:00.000000000 +0000 @@ -1,6 +1,11 @@ package org.bouncycastle.jce.provider; import java.security.Permission; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import javax.crypto.spec.DHParameterSpec; @@ -20,12 +25,18 @@ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS); private static Permission BC_DH_PERMISSION = new ProviderConfigurationPermission( BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.DH_DEFAULT_PARAMS); + private static Permission BC_EC_CURVE_PERMISSION = new ProviderConfigurationPermission( + BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.ACCEPTABLE_EC_CURVES); + private static Permission BC_ADDITIONAL_EC_CURVE_PERMISSION = new ProviderConfigurationPermission( + BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.ADDITIONAL_EC_PARAMETERS); private ThreadLocal ecThreadSpec = new ThreadLocal(); private ThreadLocal dhThreadSpec = new ThreadLocal(); private volatile ECParameterSpec ecImplicitCaParams; private volatile Object dhDefaultParams; + private volatile Set acceptableNamedCurves = new HashSet(); + private volatile Map additionalECParameters = new HashMap(); void setParameter(String parameterName, Object parameter) { @@ -117,6 +128,24 @@ throw new IllegalArgumentException("not a valid DHParameterSpec or DHParameterSpec[]"); } } + else if (parameterName.equals(ConfigurableProvider.ACCEPTABLE_EC_CURVES)) + { + if (securityManager != null) + { + securityManager.checkPermission(BC_EC_CURVE_PERMISSION); + } + + this.acceptableNamedCurves = (Set)parameter; + } + else if (parameterName.equals(ConfigurableProvider.ADDITIONAL_EC_PARAMETERS)) + { + if (securityManager != null) + { + securityManager.checkPermission(BC_ADDITIONAL_EC_CURVE_PERMISSION); + } + + this.additionalECParameters = (Map)parameter; + } } public ECParameterSpec getEcImplicitlyCa() @@ -163,4 +192,14 @@ return null; } + + public Set getAcceptableNamedCurves() + { + return Collections.unmodifiableSet(acceptableNamedCurves); + } + + public Map getAdditionalECParameters() + { + return Collections.unmodifiableMap(additionalECParameters); + } } diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java 2015-09-22 02:12:13.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java 2016-09-08 01:28:07.000000000 +0000 @@ -22,6 +22,7 @@ suite.addTestSuite(ECAlgorithmParametersTest.class); suite.addTestSuite(PrivateConstructorTest.class); + suite.addTestSuite(RandomTest.class); return new BCTestSetup(suite); } diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECAlgorithmParametersTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECAlgorithmParametersTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECAlgorithmParametersTest.java 2015-11-27 21:38:59.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECAlgorithmParametersTest.java 2016-11-21 02:42:02.000000000 +0000 @@ -136,47 +136,54 @@ "X9.62 c2pnb304w1", "1.2.840.10045.3.0.17", "X9.62 c2pnb368w1", - "1.2.840.10045.3.0.19" }; + "1.2.840.10045.3.0.19"}; public void testRecogniseStandardCurveNames() throws Exception { Security.addProvider(new BouncyCastleProvider()); - for (int i = 0; i != entries.length; i++) - { - AlgorithmParameters algParams = AlgorithmParameters.getInstance("EC", "BC"); + int testCount = 0; - algParams.init(new ECGenParameterSpec(entries[i])); + for (int i = 0; i != entries.length; i++) + { + AlgorithmParameters algParams = AlgorithmParameters.getInstance("EC", "BC"); - ECParameterSpec ecSpec = null; + try + { + algParams.init(new ECGenParameterSpec(entries[i])); + } + catch (IllegalArgumentException e) + { + // ignore - this is due to a JDK 1.5 bug + continue; + } - try - { - ecSpec = algParams.getParameterSpec(ECParameterSpec.class); - } - catch (IllegalArgumentException e) - { - // ignore - this is due to a JDK 1.5 bug - } + testCount++; + ECParameterSpec ecSpec = null; - ECGenParameterSpec spec = algParams.getParameterSpec(ECGenParameterSpec.class); + ecSpec = algParams.getParameterSpec(ECParameterSpec.class); - TestCase.assertEquals(nextOid(i), spec.getName()); - if (ecSpec != null) - { - AlgorithmParameters algParams2 = AlgorithmParameters.getInstance("EC", "BC"); + ECGenParameterSpec spec = algParams.getParameterSpec(ECGenParameterSpec.class); - algParams2.init(new ECParameterSpec(ecSpec.getCurve(), ecSpec.getGenerator(), ecSpec.getOrder(), ecSpec.getCofactor())); + TestCase.assertEquals(nextOid(i), spec.getName()); - spec = algParams2.getParameterSpec(ECGenParameterSpec.class); + if (ecSpec != null) + { + AlgorithmParameters algParams2 = AlgorithmParameters.getInstance("EC", "BC"); - TestCase.assertEquals(nextOid(i), spec.getName()); + algParams2.init(new ECParameterSpec(ecSpec.getCurve(), ecSpec.getGenerator(), ecSpec.getOrder(), ecSpec.getCofactor())); - algParams.getEncoded(); // check that we can get an encoded spec. - } - } + spec = algParams2.getParameterSpec(ECGenParameterSpec.class); + + TestCase.assertEquals(nextOid(i), spec.getName()); + + algParams.getEncoded(); // check that we can get an encoded spec. + } + } + + TestCase.assertTrue(testCount != 0); // at least one test must work! } private String nextOid(int index) diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java 2016-12-20 04:26:16.000000000 +0000 @@ -0,0 +1,48 @@ +package org.bouncycastle.jcajce.provider.test; + +import java.security.SecureRandom; + +import junit.framework.Assert; +import junit.framework.TestCase; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +public class RandomTest + extends TestCase +{ + public void testCheckRandom() + throws Exception + { + SecureRandom random = SecureRandom.getInstance("DEFAULT", new BouncyCastleProvider()); + + byte[] rng = new byte[20]; + + random.nextBytes(rng); + + Assert.assertTrue(checkNonConstant(rng)); + } + + public void testCheckNonceIVRandom() + throws Exception + { + SecureRandom random = SecureRandom.getInstance("NONCEANDIV", new BouncyCastleProvider()); + + byte[] rng = new byte[20]; + + random.nextBytes(rng); + + Assert.assertTrue(checkNonConstant(rng)); + } + + private boolean checkNonConstant(byte[] data) + { + for (int i = 1; i != data.length; i++) + { + if (data[i] != data[i - 1]) + { + return true; + } + } + + return false; + } +} diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/AEADTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/AEADTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/AEADTest.java 2015-09-04 07:42:49.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/AEADTest.java 2016-12-16 22:26:15.000000000 +0000 @@ -18,7 +18,9 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import junit.framework.TestCase; import org.bouncycastle.asn1.cms.GCMParameters; +import org.bouncycastle.jcajce.spec.AEADParameterSpec; import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.Arrays; @@ -57,6 +59,7 @@ catch (ClassNotFoundException e) { } + testAEADParameterSpec(K2, N2, A2, P2, C2); if (aeadAvailable) { checkCipherWithAD(K2, N2, A2, P2, C2_short); @@ -64,6 +67,7 @@ testGCMParameterSpecWithRepeatKey(K2, N2, A2, P2, C2); testGCMGeneric(KGCM, NGCM, new byte[0], new byte[0], CGCM); testGCMParameterSpecWithMultipleUpdates(K2, N2, A2, P2, C2); + testRepeatedGCMWithSpec(KGCM, NGCM, A2, P2, Hex.decode("f4732d84342623f65b7d63c3c335dd44b87d")); } else { @@ -139,6 +143,74 @@ } } + private void testAEADParameterSpec(byte[] K, + byte[] N, + byte[] A, + byte[] P, + byte[] C) + throws Exception + { + Cipher eax = Cipher.getInstance("AES/EAX/NoPadding", "BC"); + SecretKeySpec key = new SecretKeySpec(K, "AES"); + + AEADParameterSpec spec = new AEADParameterSpec(N, 128, A); + eax.init(Cipher.ENCRYPT_MODE, key, spec); + + byte[] c = eax.doFinal(P); + + if (!Arrays.areEqual(C, c)) + { + TestCase.fail("JCE encrypt with additional data and AEADParameterSpec failed."); + } + + // doFinal test + c = eax.doFinal(P); + + if (!Arrays.areEqual(C, c)) + { + TestCase.fail("JCE encrypt with additional data and AEADParameterSpec failed after do final"); + } + + eax.init(Cipher.DECRYPT_MODE, key, spec); + + byte[] p = eax.doFinal(C); + + if (!Arrays.areEqual(P, p)) + { + TestCase.fail("JCE decrypt with additional data and AEADParameterSpec failed."); + } + + AlgorithmParameters algParams = eax.getParameters(); + + byte[] encParams = algParams.getEncoded(); + + GCMParameters gcmParameters = GCMParameters.getInstance(encParams); + + if (!Arrays.areEqual(spec.getIV(), gcmParameters.getNonce()) || spec.getMacSizeInBits() != gcmParameters.getIcvLen() * 8) + { + TestCase.fail("parameters mismatch"); + } + + // note: associated data is not preserved + AEADParameterSpec cSpec = algParams.getParameterSpec(AEADParameterSpec.class); + if (!Arrays.areEqual(spec.getIV(), cSpec.getNonce()) || spec.getMacSizeInBits() != cSpec.getMacSizeInBits() + || cSpec.getAssociatedData() != null) + { + TestCase.fail("parameters mismatch"); + } + + AlgorithmParameters aeadParams = AlgorithmParameters.getInstance("GCM", "BC"); + + aeadParams.init(spec); + + cSpec = aeadParams.getParameterSpec(AEADParameterSpec.class); + if (!Arrays.areEqual(spec.getIV(), cSpec.getNonce()) || spec.getMacSizeInBits() != cSpec.getMacSizeInBits() + || cSpec.getAssociatedData() != null) + { + TestCase.fail("parameters mismatch"); + } + } + private void testGCMParameterSpec(byte[] K, byte[] N, byte[] A, @@ -346,6 +418,69 @@ } } + private void testRepeatedGCMWithSpec(byte[] K, + byte[] N, + byte[] A, + byte[] P, + byte[] C) + throws InvalidKeyException, NoSuchAlgorithmException, + NoSuchPaddingException, IllegalBlockSizeException, + BadPaddingException, InvalidAlgorithmParameterException, NoSuchProviderException, IOException + { + Cipher eax = Cipher.getInstance("AES/GCM/NoPadding", "BC"); + SecretKeySpec key = new SecretKeySpec(K, "AES"); + GCMParameterSpec spec = new GCMParameterSpec(128, N); + eax.init(Cipher.ENCRYPT_MODE, key, spec); + + eax.updateAAD(A); + byte[] c = eax.doFinal(P); + + if (!areEqual(C, c)) + { + fail("JCE encrypt with additional data and RepeatedSecretKeySpec failed."); + } + + eax = Cipher.getInstance("GCM", "BC"); + eax.init(Cipher.DECRYPT_MODE, key, spec); + eax.updateAAD(A); + byte[] p = eax.doFinal(C); + + if (!areEqual(P, p)) + { + fail("JCE decrypt with additional data and GCMParameterSpec failed."); + } + + try + { + eax.init(Cipher.ENCRYPT_MODE, new RepeatedSecretKeySpec("AES"), spec); + fail("no exception"); + } + catch (InvalidKeyException e) + { + isTrue("wrong message", "cannot reuse nonce for GCM encryption".equals(e.getMessage())); + } + + try + { + eax.init(Cipher.ENCRYPT_MODE, new RepeatedSecretKeySpec("AES"), new IvParameterSpec(spec.getIV())); + fail("no exception"); + } + catch (InvalidKeyException e) + { + isTrue("wrong message", "cannot reuse nonce for GCM encryption".equals(e.getMessage())); + } + + try + { + eax.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(K, "AES"), new IvParameterSpec(spec.getIV())); + fail("no exception"); + } + catch (InvalidKeyException e) + { + isTrue("wrong message", "cannot reuse nonce for GCM encryption".equals(e.getMessage())); + } + } + public static void main(String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java 2015-11-27 07:04:41.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java 2016-09-14 11:14:23.000000000 +0000 @@ -105,9 +105,9 @@ AlgorithmParameters al = AlgorithmParameters.getInstance("EC", "BC"); - al.init(new ECGenParameterSpec(SECObjectIdentifiers.secp224k1.getId())); + al.init(new ECGenParameterSpec(SECObjectIdentifiers.secp256r1.getId())); - if (!Arrays.areEqual(Hex.decode("06052b81040020"), al.getEncoded())) + if (!Arrays.areEqual(Hex.decode("06082a8648ce3d030107"), al.getEncoded())) { fail("EC param test failed"); } diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java 2016-12-19 01:29:09.000000000 +0000 @@ -0,0 +1,781 @@ +package org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.util.Date; +import java.util.Enumeration; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.test.SimpleTest; + +/** + * Exercise the BCFKS KeyStore, + */ +public class BCFKSStoreTest + extends SimpleTest +{ + private static byte[] trustedCertData = Base64.decode( + "MIIB/DCCAaagAwIBAgIBATANBgkqhkiG9w0BAQQFADCBhjELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb24gb2YgdGhlIE" + + "JvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExJjAkBgkqhkiG9w0BCQEWF2lzc3VlckBi" + + "b3VuY3ljYXN0bGUub3JnMB4XDTE0MDIyODExMjcxMVoXDTE0MDQyOTExMjcxMVowgYcxCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaG" + + "UgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMScwJQYJKoZI" + + "hvcNAQkBFhhzdWJqZWN0QGJvdW5jeWNhc3RsZS5vcmcwWjANBgkqhkiG9w0BAQEFAANJADBGAkEAtKfkYXBXTxapcIKyK+WLaipil5" + + "hBm+EocqS9umJs+umQD3ar+xITnc5d5WVk+rK2VDFloEDGBoh0IOM9ke1+1wIBETANBgkqhkiG9w0BAQQFAANBAJ/ZhfF21NykhbEY" + + "RQrAo/yRr9XfpmBTVUSlLJXYoNVVRT5u9SGQqmPNfHElrTvNMZQPC0ridDZtBWb6S2tg9/E="); + + static char[] testPassword = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}; + static char[] invalidTestPassword = {'Y', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}; + + + public void shouldCreateEmptyBCFKSNoPassword() + throws Exception + { + checkEmptyStore(null); + } + + public void shouldCreateEmptyBCFKSPassword() + throws Exception + { + checkEmptyStore(testPassword); + } + + private void checkEmptyStore(char[] passwd) + throws KeyStoreException, NoSuchProviderException, IOException, NoSuchAlgorithmException, CertificateException + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + } + + private void checkInvalidLoad(KeyStore store, char[] passwd, byte[] data) + throws NoSuchAlgorithmException, CertificateException, KeyStoreException + { + checkInvalidLoadForPassword(store, invalidTestPassword, data); + + if (passwd != null) + { + checkInvalidLoadForPassword(store, null, data); + } + } + + private void checkInvalidLoadForPassword(KeyStore store, char[] password, byte[] data) + throws NoSuchAlgorithmException, CertificateException, KeyStoreException + { + try + { + store.load(new ByteArrayInputStream(data), password); + } + catch (IOException e) + { + isTrue("wrong message", "BCFKS KeyStore corrupted: MAC calculation failed.".equals(e.getMessage())); + } + + isTrue("", 0 == store.size()); + isTrue("", !store.aliases().hasMoreElements()); + } + + public void shouldStoreOneCertificate() + throws Exception + { + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + checkOneCertificate(cert, null); + checkOneCertificate(cert, testPassword); + } + + private void checkOneCertificate(X509Certificate cert, char[] passwd) + throws KeyStoreException, NoSuchProviderException, IOException, NoSuchAlgorithmException, CertificateException + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setCertificateEntry("cert", cert); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "cert".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + certStorageCheck(store1, "cert", cert); + + Date entryDate = store1.getCreationDate("cert"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", entryDate.equals(store2.getCreationDate("cert"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "cert".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + certStorageCheck(store2, "cert", cert); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("cert"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + public void shouldStoreOnePrivateKey() + throws Exception + { + PrivateKey privKey = getPrivateKey(); + + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + checkOnePrivateKeyFips(privKey, new X509Certificate[] { cert }, null); + checkOnePrivateKeyFips(privKey, new X509Certificate[] { cert }, testPassword); + checkOnePrivateKeyDef(privKey, new X509Certificate[] { cert }, null); + checkOnePrivateKeyDef(privKey, new X509Certificate[] { cert }, testPassword); + } + + public void shouldStoreOnePrivateKeyWithChain() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(512); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withRSA", + null, + kp1.getPublic()); + + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + } + + public void shouldStoreOneECKeyWithChain() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC"); + + kpGen.initialize(256); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withECDSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withECDSA", + null, + kp1.getPublic()); + + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + } + + public void shouldRejectInconsistentKeys() + throws Exception + { + PrivateKey privKey = getPrivateKey(); + + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.interCertBin)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + try + { + store1.setKeyEntry("privkey", privKey, "hello".toCharArray(), new X509Certificate[]{interCert}); + fail("no exception"); + } + catch (KeyStoreException e) + { + isTrue("", "RSA keys do not have the same modulus".equals(e.getCause().getMessage())); + } + } + + private void checkOnePrivateKeyFips(PrivateKey key, X509Certificate[] certs, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + checkOnePrivateKey(key, store1, certs, passwd); + } + + private void checkOnePrivateKeyDef(PrivateKey key, X509Certificate[] certs, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS-DEF", "BC"); + + store1.load(null, null); + + checkOnePrivateKey(key, store1, certs, passwd); + } + + private void checkOnePrivateKey(PrivateKey key, KeyStore store1, X509Certificate[] certs, char[] passwd) + throws Exception + { + store1.setKeyEntry("privkey", key, passwd, certs); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "privkey".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + privateKeyStorageCheck(store1, "privkey", key, certs[0], passwd); + + Date entryDate = store1.getCreationDate("privkey"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", store2.getCertificateChain("privkey").length == certs.length); + Certificate[] sChain = store2.getCertificateChain("privkey"); + for (int i = 0; i != sChain.length; i++) + { + isTrue("", certs[i].equals(sChain[i])); + } + isTrue("", entryDate.equals(store2.getCreationDate("privkey"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "privkey".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + privateKeyStorageCheck(store2, "privkey", key, certs[0], passwd); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("privkey"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + public void shouldStoreMultipleKeys() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(512); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withRSA", + null, + kp1.getPublic()); + + PrivateKey privKey = kp1.getPrivate(); + + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(trustedCertData)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setKeyEntry("privkey", privKey, testPassword, new X509Certificate[]{interCert, finalCert}); + store1.setCertificateEntry("trusted", cert); + SecretKeySpec aesKey = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "AES"); + store1.setKeyEntry("secret1", aesKey, "secretPwd1".toCharArray(), null); + SecretKeySpec edeKey = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "DESede"); + store1.setKeyEntry("secret2", edeKey, "secretPwd2".toCharArray(), null); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, testPassword); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), testPassword); + + isTrue("", 4 ==store2.size()); + + Key storeDesEde = store2.getKey("secret2", "secretPwd2".toCharArray()); + + isTrue("", edeKey.getAlgorithm().equals(storeDesEde.getAlgorithm())); + + isTrue("", Arrays.areEqual(edeKey.getEncoded(), storeDesEde.getEncoded())); + + Key storeAes = store2.getKey("secret1", "secretPwd1".toCharArray()); + isTrue("", Arrays.areEqual(aesKey.getEncoded(), storeAes.getEncoded())); + isTrue("", aesKey.getAlgorithm().equals(storeAes.getAlgorithm())); + + Key storePrivKey = store2.getKey("privkey", testPassword); + isTrue("", privKey.equals(storePrivKey)); + isTrue("", 2 == store2.getCertificateChain("privkey").length); + + Certificate storeCert = store2.getCertificate("trusted"); + isTrue("", cert.equals(storeCert)); + + isTrue("", null ==store2.getCertificate("unknown")); + + isTrue("", null ==store2.getCertificateChain("unknown")); + + isTrue("", !store2.isCertificateEntry("unknown")); + + isTrue("", !store2.isKeyEntry("unknown")); + + isTrue("", !store2.containsAlias("unknown")); + } + + public void shouldStoreSecretKeys() + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + SecretKeySpec aesKey = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "AES"); + SecretKeySpec edeKey1 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "DESede"); + SecretKeySpec edeKey2 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "TripleDES"); + SecretKeySpec edeKey3 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "TDEA"); + SecretKeySpec hmacKey1 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff"), "HmacSHA1"); + SecretKeySpec hmacKey224 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff"), "HmacSHA224"); + SecretKeySpec hmacKey256 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff01ff"), "HmacSHA256"); + SecretKeySpec hmacKey384 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff0102ff"), "HmacSHA384"); + SecretKeySpec hmacKey512 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff010203ff"), "HmacSHA512"); + + store1.setKeyEntry("secret1", aesKey, "secretPwd1".toCharArray(), null); + store1.setKeyEntry("secret2", edeKey1, "secretPwd2".toCharArray(), null); + store1.setKeyEntry("secret3", edeKey2, "secretPwd3".toCharArray(), null); + store1.setKeyEntry("secret4", edeKey3, "secretPwd4".toCharArray(), null); + store1.setKeyEntry("secret5", hmacKey1, "secretPwd5".toCharArray(), null); + store1.setKeyEntry("secret6", hmacKey224, "secretPwd6".toCharArray(), null); + store1.setKeyEntry("secret7", hmacKey256, "secretPwd7".toCharArray(), null); + store1.setKeyEntry("secret8", hmacKey384, "secretPwd8".toCharArray(), null); + store1.setKeyEntry("secret9", hmacKey512, "secretPwd9".toCharArray(), null); + + checkSecretKey(store1, "secret1", "secretPwd1".toCharArray(), aesKey); + checkSecretKey(store1, "secret2", "secretPwd2".toCharArray(), edeKey1); // TRIPLEDES and TDEA will convert to DESEDE + checkSecretKey(store1, "secret3", "secretPwd3".toCharArray(), edeKey1); + checkSecretKey(store1, "secret4", "secretPwd4".toCharArray(), edeKey1); + checkSecretKey(store1, "secret5", "secretPwd5".toCharArray(), hmacKey1); + checkSecretKey(store1, "secret6", "secretPwd6".toCharArray(), hmacKey224); + checkSecretKey(store1, "secret7", "secretPwd7".toCharArray(), hmacKey256); + checkSecretKey(store1, "secret8", "secretPwd8".toCharArray(), hmacKey384); + checkSecretKey(store1, "secret9", "secretPwd9".toCharArray(), hmacKey512); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, "secretkeytest".toCharArray()); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), "secretkeytest".toCharArray()); + + checkSecretKey(store2, "secret1", "secretPwd1".toCharArray(), aesKey); + checkSecretKey(store2, "secret2", "secretPwd2".toCharArray(), edeKey1); // TRIPLEDES and TDEA will convert to DESEDE + checkSecretKey(store2, "secret3", "secretPwd3".toCharArray(), edeKey1); + checkSecretKey(store2, "secret4", "secretPwd4".toCharArray(), edeKey1); + checkSecretKey(store2, "secret5", "secretPwd5".toCharArray(), hmacKey1); + checkSecretKey(store2, "secret6", "secretPwd6".toCharArray(), hmacKey224); + checkSecretKey(store2, "secret7", "secretPwd7".toCharArray(), hmacKey256); + checkSecretKey(store2, "secret8", "secretPwd8".toCharArray(), hmacKey384); + checkSecretKey(store2, "secret9", "secretPwd9".toCharArray(), hmacKey512); + + isTrue("", null ==store2.getKey("secret10", new char[0])); + } + + private void checkSecretKey(KeyStore store, String alias, char[] passwd, SecretKey key) + throws Exception + { + SecretKey sKey = (SecretKey)store.getKey(alias, passwd); + + isTrue("", Arrays.areEqual(key.getEncoded(), sKey.getEncoded())); + isTrue("", key.getAlgorithm().equals(sKey.getAlgorithm())); + + if (!store.isKeyEntry(alias)) + { + fail("key not identified as key entry"); + } + if (!store.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) + { + fail("not identified as key entry via SecretKeyEntry"); + } + } + + private PrivateKey getPrivateKey() + { + PrivateKey privKey = null; + + RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16), + new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16), + new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16), + new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16), + new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16), + new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16), + new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16)); + + + try + { + KeyFactory fact = KeyFactory.getInstance("RSA", "BC"); + + privKey = fact.generatePrivate(privKeySpec); + } + catch (Exception e) + { + fail("error setting up keys - " + e.toString()); + } + + return privKey; + } + + public void shouldStoreOneSecretKey() + throws Exception + { + checkOneSecretKey(new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "AES"), null); + checkOneSecretKey(new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "AES"), testPassword); + } + + private void checkOneSecretKey(SecretKey key, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setKeyEntry("seckey", key, passwd, null); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "seckey".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + secretKeyStorageCheck(store1, "seckey", key, passwd); + + Date entryDate = store1.getCreationDate("seckey"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", entryDate.equals(store2.getCreationDate("seckey"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "seckey".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + secretKeyStorageCheck(store2, "seckey", key, passwd); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("seckey"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + private void privateKeyStorageCheck(KeyStore store, String keyName, PrivateKey key, Certificate cert, char[] password) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException + { + if (!store.containsAlias(keyName)) + { + fail("couldn't find alias privateKey"); + } + + if (store.isCertificateEntry(keyName)) + { + fail("key identified as certificate entry"); + } + + if (!store.isKeyEntry(keyName)) + { + fail("key not identified as key entry"); + } + + Key storeKey = store.getKey(keyName, password); + + if (store.getType().equals("BCFKS")) + { + isTrue("", key.equals(storeKey)); + } + + if (password != null) + { + try + { + store.getKey(keyName, null); + } + catch (UnrecoverableKeyException e) + { + isTrue("",e.getMessage().startsWith("BCFKS KeyStore unable to recover private key (privkey)")); + } + } + + Certificate[] certificateChain = store.getCertificateChain(keyName); + if (certificateChain == null) + { + fail("Did not return certificate chain"); + } + isTrue("", cert.equals(certificateChain[0])); + + isTrue("", keyName.equals(store.getCertificateAlias(cert))); + + if (store.entryInstanceOf(keyName, KeyStore.TrustedCertificateEntry.class)) + { + fail("identified as TrustedCertificateEntry"); + } + + if (!store.entryInstanceOf(keyName, KeyStore.PrivateKeyEntry.class)) + { + fail("not identified as key entry via PrivateKeyEntry"); + } + + if (store.entryInstanceOf(keyName, KeyStore.SecretKeyEntry.class)) + { + fail("identified as key entry via SecretKeyEntry"); + } + } + + private void certStorageCheck(KeyStore store, String certName, Certificate cert) + throws KeyStoreException + { + if (!store.containsAlias(certName)) + { + fail("couldn't find alias " + certName); + } + + if (!store.isCertificateEntry(certName)) + { + fail("cert not identified as certificate entry"); + } + + if (store.isKeyEntry(certName)) + { + fail("cert identified as key entry"); + } + + if (!store.entryInstanceOf(certName, KeyStore.TrustedCertificateEntry.class)) + { + fail("cert not identified as TrustedCertificateEntry"); + } + + if (store.entryInstanceOf(certName, KeyStore.PrivateKeyEntry.class)) + { + fail("cert identified as key entry via PrivateKeyEntry"); + } + + if (store.entryInstanceOf(certName, KeyStore.SecretKeyEntry.class)) + { + fail("cert identified as key entry via SecretKeyEntry"); + } + + if (!certName.equals(store.getCertificateAlias(cert))) + { + fail("Did not return alias for certificate entry"); + } + } + + private void secretKeyStorageCheck(KeyStore store, String keyName, SecretKey key, char[] password) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException + { + if (!store.containsAlias(keyName)) + { + fail("couldn't find alias privateKey"); + } + + if (store.isCertificateEntry(keyName)) + { + fail("key identified as certificate entry"); + } + + if (!store.isKeyEntry(keyName)) + { + fail("key not identified as key entry"); + } + + Key storeKey = store.getKey(keyName, password); + + isTrue("", Arrays.areEqual(key.getEncoded(), storeKey.getEncoded())); + + if (password != null) + { + try + { + store.getKey(keyName, null); + } + catch (UnrecoverableKeyException e) + { + isTrue("", e.getMessage().startsWith("BCFKS KeyStore unable to recover secret key (seckey)")); + } + } + + Certificate[] certificateChain = store.getCertificateChain(keyName); + if (certificateChain != null) + { + fail("returned certificates!"); + } + + if (store.entryInstanceOf(keyName, KeyStore.TrustedCertificateEntry.class)) + { + fail("identified as TrustedCertificateEntry"); + } + + if (store.entryInstanceOf(keyName, KeyStore.PrivateKeyEntry.class)) + { + fail("identified as key entry via PrivateKeyEntry"); + } + + if (!store.entryInstanceOf(keyName, KeyStore.SecretKeyEntry.class)) + { + fail("not identified as key entry via SecretKeyEntry"); + } + } + + public String getName() + { + return "BCFKS"; + } + + public void performTest() + throws Exception + { + shouldCreateEmptyBCFKSNoPassword(); + shouldCreateEmptyBCFKSPassword(); + shouldStoreMultipleKeys(); + shouldStoreOneCertificate(); + shouldStoreOneECKeyWithChain(); + shouldStoreOnePrivateKey(); + shouldStoreOnePrivateKeyWithChain(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new BCFKSStoreTest()); + } +} diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/CertTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/CertTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/CertTest.java 2016-08-10 04:18:32.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/CertTest.java 2016-10-20 23:28:47.000000000 +0000 @@ -1104,6 +1104,31 @@ "AGfsxfTyldQDEOVzD/Uq8Xh4gIHuSqki9mRSjMR19MQtTKRmI9TRHIeTdIZ6l3P7" + "jFfGJvTP0E9NYSolx+kM"); + private final byte[] sha3Cert = Base64.decode( + "MIID8jCCAqagAwIBAgIICfBykpzUT+IwQQYJKoZIhvcNAQEKMDSgDzANBglg" + + "hkgBZQMEAggFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAggFAKIDAgEg" + + "MCwxCzAJBgNVBAYTAkRFMQ4wDAYDVQQKDAV4aXBraTENMAsGA1UEAwwEUkNB" + + "MTAeFw0xNjEwMTgxODQzMjhaFw0yNjEwMTgxODQzMjdaMCwxCzAJBgNVBAYT" + + "AkRFMQ4wDAYDVQQKDAV4aXBraTENMAsGA1UEAwwEUkNBMTCCASIwDQYJKoZI" + + "hvcNAQEBBQADggEPADCCAQoCggEBAK/pzm1RASDYDg3WBXyW3AnAESRF/+li" + + "qh0X8Y89m+JFJeOi1u89bOSPjsFfo5SbRSElyRXedh/d37KrONg39NEKIcC6" + + "iSuiNfXu0D6nlSzhrQzmvHIyfLnm8N2JtHDr/hZIprOcFO+lZTJIjjrOVe9y" + + "lFGgGDd/uQCEJk1Cmi5Ivi9odeiN3z8lVlGNeN9/Q5n47ijuYWr73z/FyyAK" + + "gAG3B5nhAYWs4ft0O3JWBc0QJZzShqsRjm3SNhAqMDnRoTq04PFgbDYizV8T" + + "ydz2kCne79TDwsY4MckYYaGoNcPoQXVS+9YjQjI72ktSlxiJxodL9WMFl+ED" + + "5ZLBRIRsDJECAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MGoGCCsGAQUF" + + "BwEBBF4wXDAnBggrBgEFBQcwAoYbaHR0cDovL2V4YW1wbGUub3JnL1JDQTEu" + + "ZGVyMDEGCCsGAQUFBzABhiVodHRwOi8vbG9jYWxob3N0OjgwODAvb2NzcC9y" + + "ZXNwb25kZXIxMB0GA1UdDgQWBBRTXKdJI3P1kveLlRxPvzUfDnC8JjAOBgNV" + + "HQ8BAf8EBAMCAQYwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAggFAKEc" + + "MBoGCSqGSIb3DQEBCDANBglghkgBZQMEAggFAKIDAgEgA4IBAQCpSVaqOMKz" + + "6NT0+mivEhig9cKsglFhnWStKUtdhrG4HqOf6Qjny9Xvq1nE7x8e2xAoaZLd" + + "GMsNAWFCbwzoJrDL7Ct6itQ5ymxi2haN+Urc5UWJd/8C0R74OdP1uPCiljZ9" + + "DdjbNk/hS36UPYi+FT5r6Jr/1X/EqgL1MOUsSTEXdYlZH662zjbV4D9QSBzx" + + "ul9bYyWrqSZFKvKef4UQwUy8yXtChwiwp50mfJQBdVcIqPBYCgmLYclamjQx" + + "hlkk5VbZb4D/Cv4HxrdxpJfy/ewUZR7uHlzDx0/m4qjzNzWgq+sh3ZbveDrV" + + "wd/FDMFOxSIno9qgHtdfgXRwZJ+l07fF"); + private final String ecPemCert = "-----BEGIN CERTIFICATE-----\n" + "MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC\n" + @@ -1701,6 +1726,8 @@ } } + checkSelfSignedCertificate(23, sha3Cert, "SHA3-256withRSAandMGF1"); + checkCRL(1, crl1); pemTest(); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest2.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest2.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest2.java 2014-11-18 04:49:28.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest2.java 2016-08-31 00:49:47.000000000 +0000 @@ -1,10 +1,15 @@ package org.bouncycastle.jce.provider.test; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.security.Key; import java.security.Security; -import javax.crypto.*; +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; import javax.crypto.spec.IvParameterSpec; import org.bouncycastle.crypto.io.InvalidCipherTextIOException; @@ -499,6 +504,7 @@ "SALSA20", "XSalsa20", "ChaCha", + "ChaCha7539", "Grainv1", "Grain128", "HC128", diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java 2015-03-08 04:56:36.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java 2016-08-31 00:47:53.000000000 +0000 @@ -63,6 +63,15 @@ + "D44A7A7CDB84929F915420A8A3DC58BF" + "0F7ECB4B1F167BB1A5E6153FDAF4493D"); + private static final byte[] CHA7539K = Hex.decode("8000000000000000000000000000000080000000000000000000000000000000"); + private static final byte[] CHA7539IV = Hex.decode("000000000000000000000000"); + private static final byte[] CHA7539IN = Hex.decode( + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"); + private static final byte[] CHA7539OUT = Hex.decode("aef50e541e12a65dc21e90ebb4c03987971c540f78eb536df692ff89fc47561ed17eb23b63eb714c09d0c50af703e01485926c140e994b3edff9df635a91d268"); + private static final byte[] HCIN = new byte[64]; private static final byte[] HCIV = new byte[32]; @@ -259,7 +268,7 @@ (byte)137, (byte)138, (byte)140, (byte)143 }; byte[] keyBytes; - if (name.equals("HC256") || name.equals("XSalsa20")) + if (name.equals("HC256") || name.equals("XSalsa20") || name.equals("ChaCha7539")) { keyBytes = key256; } @@ -377,6 +386,9 @@ runTest("ChaCha"); testException("ChaCha"); testAlgorithm("ChaCha", CHAK, CHAIV, CHAIN, CHAOUT); + runTest("ChaCha7539"); + testException("ChaCha7539"); + testAlgorithm("ChaCha7539", CHA7539K, CHA7539IV, CHA7539IN, CHA7539OUT); runTest("HC128"); testException("HC128"); testAlgorithm("HC128", HCK128A, HCIV, HCIN, HC128A); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/DHIESTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/DHIESTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/DHIESTest.java 2013-05-29 01:07:55.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/DHIESTest.java 2016-10-29 03:06:57.000000000 +0000 @@ -1,11 +1,13 @@ package org.bouncycastle.jce.provider.test; import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.SecureRandom; import java.security.Security; +import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.interfaces.DHPrivateKey; import javax.crypto.interfaces.DHPublicKey; @@ -18,9 +20,10 @@ import org.bouncycastle.crypto.generators.KDF2BytesGenerator; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; -import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jcajce.provider.asymmetric.dh.IESCipher; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.IESParameterSpec; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; @@ -65,17 +68,18 @@ // Testing DHIES with default prime in streaming mode KeyPairGenerator g = KeyPairGenerator.getInstance("DH", "BC"); + KeyPairGenerator g512 = KeyPairGenerator.getInstance("DH", "BC"); g.initialize(param); doTest("DHIES with default", g, "DHIES", params); // Testing DHIES with 512-bit prime in streaming mode - g.initialize(512, new SecureRandom()); - doTest("DHIES with 512-bit", g, "DHIES", params); + g512.initialize(512, new SecureRandom()); + doTest("DHIES with 512-bit", g512, "DHIES", params); // Testing ECIES with 1024-bit prime in streaming mode - g.initialize(1024, new SecureRandom()); + g.initialize(param, new SecureRandom()); doTest("DHIES with 1024-bit", g, "DHIES", params); c1 = new IESCipher(new IESEngine(new DHBasicAgreement(), @@ -88,43 +92,79 @@ new HMac(new SHA1Digest()), new PaddedBufferedBlockCipher(new DESEngine()))); - params = new IESParameterSpec(derivation, encoding, 128, 192); + params = new IESParameterSpec(derivation, encoding, 128, 192, Hex.decode("0001020304050607")); // Testing DHIES with default prime using DESEDE g = KeyPairGenerator.getInstance("DH", "BC"); - doTest("DHIESwithDES default", g, "DHIESwithDESEDE", params); + doTest("DHIESwithDES default", g, "DHIESwithDESEDE-CBC", params); // Testing DHIES with 512-bit prime using DESEDE - g.initialize(512, new SecureRandom()); - doTest("DHIESwithDES 512-bit", g, "DHIESwithDESEDE", params); + doTest("DHIESwithDES 512-bit", g512, "DHIESwithDESEDE-CBC", params); // Testing DHIES with 1024-bit prime using DESEDE - g.initialize(1024, new SecureRandom()); - doTest("DHIESwithDES 1024-bit", g, "DHIESwithDESEDE", params); + g.initialize(param, new SecureRandom()); + doTest("DHIESwithDES 1024-bit", g, "DHIESwithDESEDE-CBC", params); g = KeyPairGenerator.getInstance("DH", "BC"); g.initialize(param); - c1 = new IESCipher.IESwithAES(); - c2 = new IESCipher.IESwithAES(); - params = new IESParameterSpec(derivation, encoding, 128, 128); - - // Testing DHIES with default curve using AES - doTest("DHIESwithAES default", g, "DHIESwithAES", params); - - // Testing DHIES with 512-bit curve using AES - g.initialize(512, new SecureRandom()); - doTest("DHIESwithAES 512-bit", g, "DHIESwithAES", params); - - // Testing DHIES with 1024-bit curve using AES - g.initialize(1024, new SecureRandom()); - doTest("DHIESwithAES 1024-bit", g, "DHIESwithAES", params); - + c1 = new IESCipher.IESwithAESCBC(); + c2 = new IESCipher.IESwithAESCBC(); + params = new IESParameterSpec(derivation, encoding, 128, 128, Hex.decode("00010203040506070001020304050607")); + + // Testing DHIES with default prime using AES + doTest("DHIESwithAES default", g, "DHIESwithAES-CBC", params); + + // Testing DHIES with 512-bit prime using AES + doTest("DHIESwithAES 512-bit", g512, "DHIESwithAES-CBC", params); + + // Testing DHIES with 1024-bit prime using AES + g.initialize(param, new SecureRandom()); + doTest("DHIESwithAES 1024-bit", g, "DHIESwithAES-CBC", params); + + KeyPair keyPair = g.generateKeyPair(); + DHPublicKey pub = (DHPublicKey)keyPair.getPublic(); + DHPrivateKey priv = (DHPrivateKey)keyPair.getPrivate(); + + Cipher c = Cipher.getInstance("DHIESwithAES-CBC", "BC"); + + try + { + c.init(Cipher.ENCRYPT_MODE, pub, new IESParameterSpec(derivation, encoding, 128, 128, null)); + + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } + + try + { + c.init(Cipher.DECRYPT_MODE, priv); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isTrue("message ", "cannot handle supplied parameter spec: NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } + + try + { + c.init(Cipher.DECRYPT_MODE, priv, new IESParameterSpec(derivation, encoding, 128, 128, null)); + + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } } public void doTest( - String testname, - KeyPairGenerator g, + String testname, + KeyPairGenerator g, String cipher, IESParameterSpec p) throws Exception @@ -139,22 +179,23 @@ KeyPair keyPair = g.generateKeyPair(); DHPublicKey pub = (DHPublicKey)keyPair.getPublic(); DHPrivateKey priv = (DHPrivateKey)keyPair.getPrivate(); - - // Testing with null parameters and DHAES mode off + // Testing with default parameters and DHAES mode off c1.init(Cipher.ENCRYPT_MODE, pub, new SecureRandom()); - c2.init(Cipher.DECRYPT_MODE, priv, new SecureRandom()); + c2.init(Cipher.DECRYPT_MODE, priv, c1.getParameters()); + + isTrue("nonce mismatch", Arrays.areEqual(c1.getIV(), c2.getIV())); + out1 = c1.doFinal(message, 0, message.length); out2 = c2.doFinal(out1, 0, out1.length); if (!areEqual(out2, message)) { - fail(testname + " test failed with null parameters, DHAES mode false."); + fail(testname + " test failed with default parameters, DHAES mode false."); } - // Testing with given parameters and DHAES mode off c1.init(Cipher.ENCRYPT_MODE, pub, p, new SecureRandom()); - c2.init(Cipher.DECRYPT_MODE, priv, p, new SecureRandom()); + c2.init(Cipher.DECRYPT_MODE, priv, p); out1 = c1.doFinal(message, 0, message.length); out2 = c2.doFinal(out1, 0, out1.length); if (!areEqual(out2, message)) @@ -164,7 +205,7 @@ c1 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC"); c2 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC"); c1.init(Cipher.ENCRYPT_MODE, pub, new SecureRandom()); - c2.init(Cipher.DECRYPT_MODE, priv, new SecureRandom()); + c2.init(Cipher.DECRYPT_MODE, priv, c1.getParameters(), new SecureRandom()); out1 = c1.doFinal(message, 0, message.length); out2 = c2.doFinal(out1, 0, out1.length); if (!areEqual(out2, message)) @@ -182,6 +223,27 @@ out2 = c2.doFinal(out1, 0, out1.length); if (!areEqual(out2, message)) fail(testname + " test failed with non-null parameters, DHAES mode true."); + + // + // corrupted data test + // + byte[] tmp = new byte[out1.length]; + for (int i = 0; i != out1.length; i++) + { + System.arraycopy(out1, 0, tmp, 0, tmp.length); + tmp[i] = (byte)~tmp[i]; + + try + { + c2.doFinal(tmp, 0, tmp.length); + + fail("decrypted corrupted data"); + } + catch (BadPaddingException e) + { + isTrue("wrong message: " + e.getMessage(), "unable to process block".equals(e.getMessage())); + } + } } public static void main( diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/DHTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/DHTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/DHTest.java 2015-12-11 01:16:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/DHTest.java 2016-11-30 02:35:19.000000000 +0000 @@ -7,16 +7,21 @@ import java.math.BigInteger; import java.security.AlgorithmParameterGenerator; import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.ECFieldFp; import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; import java.security.spec.EllipticCurve; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; @@ -52,51 +57,51 @@ private BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16); private BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16); - private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16); - private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16); + private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16); + private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16); // public key with mismatched oid/parameters private byte[] oldPubEnc = Base64.decode( "MIIBnzCCARQGByqGSM4+AgEwggEHAoGBAPxSrN417g43VAM9sZRf1dt6AocAf7D6" + - "WVCtqEDcBJrMzt63+g+BNJzhXVtbZ9kp9vw8L/0PHgzv0Ot/kOLX7Khn+JalOECW" + - "YlkyBhmOVbjR79TY5u2GAlvG6pqpizieQNBCEMlUuYuK1Iwseil6VoRuA13Zm7uw" + - "WO1eZmaJtY7LAoGAQaPRCFKM5rEdkMrV9FNzeSsYRs8m3DqPnnJHpuySpyO9wUcX" + - "OOJcJY5qvHbDO5SxHXu/+bMgXmVT6dXI5o0UeYqJR7fj6pR4E6T0FwG55RFr5Ok4" + - "3C4cpXmaOu176SyWuoDqGs1RDGmYQjwbZUi23DjaaTFUly9LCYXMliKrQfEDgYQA" + - "AoGAQUGCBN4TaBw1BpdBXdTvTfCU69XDB3eyU2FOBE3UWhpx9D8XJlx4f5DpA4Y6" + - "6sQMuCbhfmjEph8W7/sbMurM/awR+PSR8tTY7jeQV0OkmAYdGK2nzh0ZSifMO1oE" + - "NNhN2O62TLs67msxT28S4/S89+LMtc98mevQ2SX+JF3wEVU="); + "WVCtqEDcBJrMzt63+g+BNJzhXVtbZ9kp9vw8L/0PHgzv0Ot/kOLX7Khn+JalOECW" + + "YlkyBhmOVbjR79TY5u2GAlvG6pqpizieQNBCEMlUuYuK1Iwseil6VoRuA13Zm7uw" + + "WO1eZmaJtY7LAoGAQaPRCFKM5rEdkMrV9FNzeSsYRs8m3DqPnnJHpuySpyO9wUcX" + + "OOJcJY5qvHbDO5SxHXu/+bMgXmVT6dXI5o0UeYqJR7fj6pR4E6T0FwG55RFr5Ok4" + + "3C4cpXmaOu176SyWuoDqGs1RDGmYQjwbZUi23DjaaTFUly9LCYXMliKrQfEDgYQA" + + "AoGAQUGCBN4TaBw1BpdBXdTvTfCU69XDB3eyU2FOBE3UWhpx9D8XJlx4f5DpA4Y6" + + "6sQMuCbhfmjEph8W7/sbMurM/awR+PSR8tTY7jeQV0OkmAYdGK2nzh0ZSifMO1oE" + + "NNhN2O62TLs67msxT28S4/S89+LMtc98mevQ2SX+JF3wEVU="); // bogus key with full PKCS parameter set private byte[] oldFullParams = Base64.decode( "MIIBIzCCARgGByqGSM4+AgEwggELAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E" + - "AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f" + - "6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv" + - "8iIDGZ3RSAHHAoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlX" + - "jrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6j" + - "fwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqAgFk" + - "AwUAAgIH0A=="); + "AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f" + + "6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv" + + "8iIDGZ3RSAHHAoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlX" + + "jrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6j" + + "fwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqAgFk" + + "AwUAAgIH0A=="); private byte[] samplePubEnc = Base64.decode( - "MIIBpjCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I8" + - "70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk" + - "n5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX" + - "Ku/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdR" + - "WVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWR" + - "bqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoC" + - "AgIAA4GEAAKBgEIiqxoUW6E6GChoOgcfNbVFclW91ITf5MFSUGQwt2R0RHoOhxvO" + - "lZhNs++d0VPATLAyXovjfgENT9SGCbuZttYcqqLdKTbMXBWPek+rfnAl9E4iEMED" + - "IDd83FJTKs9hQcPAm7zmp0Xm1bGF9CbUFjP5G02265z7eBmHDaT0SNlB"); + "MIIBpjCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I8" + + "70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk" + + "n5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX" + + "Ku/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdR" + + "WVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWR" + + "bqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoC" + + "AgIAA4GEAAKBgEIiqxoUW6E6GChoOgcfNbVFclW91ITf5MFSUGQwt2R0RHoOhxvO" + + "lZhNs++d0VPATLAyXovjfgENT9SGCbuZttYcqqLdKTbMXBWPek+rfnAl9E4iEMED" + + "IDd83FJTKs9hQcPAm7zmp0Xm1bGF9CbUFjP5G02265z7eBmHDaT0SNlB"); private byte[] samplePrivEnc = Base64.decode( - "MIIBZgIBADCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YR" + - "t1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZ" + - "UKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOu" + - "K2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0H" + - "gmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuz" + - "pnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7P" + - "SSoCAgIABEICQAZYXnBHazxXUUdFP4NIf2Ipu7du0suJPZQKKff81wymi2zfCfHh" + - "uhe9gQ9xdm4GpzeNtrQ8/MzpTy+ZVrtd29Q="); + "MIIBZgIBADCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YR" + + "t1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZ" + + "UKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOu" + + "K2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0H" + + "gmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuz" + + "pnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7P" + + "SSoCAgIABEICQAZYXnBHazxXUUdFP4NIf2Ipu7du0suJPZQKKff81wymi2zfCfHh" + + "uhe9gQ9xdm4GpzeNtrQ8/MzpTy+ZVrtd29Q="); public String getName() { @@ -104,14 +109,14 @@ } private void testGP( - String algName, - int size, - int privateValueSize, - BigInteger g, - BigInteger p) + String algName, + int size, + int privateValueSize, + BigInteger g, + BigInteger p) throws Exception { - DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); + DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algName, "BC"); @@ -124,11 +129,11 @@ // // public key encoding test // - byte[] pubEnc = aKeyPair.getPublic().getEncoded(); - KeyFactory keyFac = KeyFactory.getInstance(algName, "BC"); - X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); - DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); - DHParameterSpec spec = pubKey.getParams(); + byte[] pubEnc = aKeyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance(algName, "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); + DHParameterSpec spec = pubKey.getParams(); if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) { @@ -169,9 +174,9 @@ // // private key encoding test // - byte[] privEnc = aKeyPair.getPrivate().getEncoded(); + byte[] privEnc = aKeyPair.getPrivate().getEncoded(); PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); - DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); + DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); spec = privKey.getParams(); @@ -268,7 +273,7 @@ } private void testTwoParty(String algName, int size, int privateValueSize, KeyPairGenerator keyGen) - throws Exception + throws Exception { testTwoParty(algName, size, privateValueSize, keyGen.generateKeyPair(), keyGen.generateKeyPair()); } @@ -312,13 +317,13 @@ } private void testExplicitWrapping( - int size, - int privateValueSize, - BigInteger g, - BigInteger p) + int size, + int privateValueSize, + BigInteger g, + BigInteger p) throws Exception { - DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); + DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC"); @@ -354,7 +359,7 @@ SecretKey k1 = aKeyAgree.generateSecret(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId()); SecretKey k2 = bKeyAgree.generateSecret(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId()); - + // TODO Compare k1 and k2? } @@ -386,7 +391,7 @@ } private void testRandom( - int size) + int size) throws Exception { AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("DH", "BC"); @@ -412,14 +417,14 @@ } private void testDefault( - int privateValueSize, - BigInteger g, - BigInteger p) + int privateValueSize, + BigInteger g, + BigInteger p) throws Exception { - DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); - String algName = "DH"; - int size = p.bitLength(); + DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); + String algName = "DH"; + int size = p.bitLength(); new BouncyCastleProvider().setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, dhParams); @@ -436,11 +441,11 @@ // // public key encoding test // - byte[] pubEnc = aKeyPair.getPublic().getEncoded(); - KeyFactory keyFac = KeyFactory.getInstance(algName, "BC"); - X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); - DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); - DHParameterSpec spec = pubKey.getParams(); + byte[] pubEnc = aKeyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance(algName, "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); + DHParameterSpec spec = pubKey.getParams(); if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) { @@ -455,13 +460,13 @@ // // public key serialisation test // - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ObjectOutputStream oOut = new ObjectOutputStream(bOut); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); oOut.writeObject(aKeyPair.getPublic()); - ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); - ObjectInputStream oIn = new ObjectInputStream(bIn); + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + ObjectInputStream oIn = new ObjectInputStream(bIn); pubKey = (DHPublicKey)oIn.readObject(); spec = pubKey.getParams(); @@ -479,9 +484,9 @@ // // private key encoding test // - byte[] privEnc = aKeyPair.getPrivate().getEncoded(); + byte[] privEnc = aKeyPair.getPrivate().getEncoded(); PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); - DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); + DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); spec = privKey.getParams(); @@ -573,7 +578,7 @@ private void testECDH(String algorithm, String curveName, String cipher, int keyLen) throws Exception { - ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec("secp521r1"); + ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(curveName); KeyPairGenerator g = KeyPairGenerator.getInstance(algorithm, "BC"); g.initialize(parameterSpec); @@ -603,7 +608,7 @@ bKeyAgree.doPhase(aKeyPair.getPublic(), true); SecretKey k1 = aKeyAgree.generateSecret(cipher); - SecretKey k2 = bKeyAgree.generateSecret(cipher); + SecretKey k2 = bKeyAgree.generateSecret(cipher + "[" + keyLen + "]"); // explicit key-len if (!k1.equals(k2)) { @@ -619,18 +624,18 @@ private void testECDH(String algorithm) throws Exception { - KeyPairGenerator g = KeyPairGenerator.getInstance(algorithm, "BC"); + KeyPairGenerator g = KeyPairGenerator.getInstance(algorithm, "BC"); EllipticCurve curve = new EllipticCurve( - new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b + new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b ECParameterSpec ecSpec = new ECParameterSpec( - curve, - ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n - 1); // h + curve, + ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n + 1); // h g.initialize(ecSpec, new SecureRandom()); @@ -658,8 +663,8 @@ aKeyAgree.doPhase(bKeyPair.getPublic(), true); bKeyAgree.doPhase(aKeyPair.getPublic(), true); - BigInteger k1 = new BigInteger(aKeyAgree.generateSecret()); - BigInteger k2 = new BigInteger(bKeyAgree.generateSecret()); + BigInteger k1 = new BigInteger(aKeyAgree.generateSecret()); + BigInteger k2 = new BigInteger(bKeyAgree.generateSecret()); if (!k1.equals(k2)) { @@ -669,10 +674,10 @@ // // public key encoding test // - byte[] pubEnc = aKeyPair.getPublic().getEncoded(); - KeyFactory keyFac = KeyFactory.getInstance(algorithm, "BC"); - X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); - ECPublicKey pubKey = (ECPublicKey)keyFac.generatePublic(pubX509); + byte[] pubEnc = aKeyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance(algorithm, "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + ECPublicKey pubKey = (ECPublicKey)keyFac.generatePublic(pubX509); if (!pubKey.getW().equals(((ECPublicKey)aKeyPair.getPublic()).getW())) { @@ -689,9 +694,9 @@ // // private key encoding test // - byte[] privEnc = aKeyPair.getPrivate().getEncoded(); + byte[] privEnc = aKeyPair.getPrivate().getEncoded(); PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); - ECPrivateKey privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8); + ECPrivateKey privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8); if (!privKey.getS().equals(((ECPrivateKey)aKeyPair.getPrivate()).getS())) { @@ -705,6 +710,7 @@ } private void testExceptions() + throws Exception { try { @@ -720,12 +726,39 @@ { fail("Unexpected exception: " + e, e); } + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "BC"); + + keyGen.initialize(256); + + KeyPair kp = keyGen.generateKeyPair(); + KeyAgreement agreement = KeyAgreement.getInstance("ECDH", "BC"); + + agreement.init(kp.getPrivate()); + try + { + ECPoint fakePubPoint = new ECPoint(new BigInteger("12345"), new BigInteger("23457")); + ECPublicKeySpec fakePubSpec = new ECPublicKeySpec(fakePubPoint, ((ECPublicKey)kp.getPublic()).getParams()); + KeyFactory kf = KeyFactory.getInstance("EC", "BC"); + PublicKey fakePub = kf.generatePublic(fakePubSpec); + agreement.doPhase(fakePub, true); + + fail("no exception on dud point"); + } + catch (java.security.spec.InvalidKeySpecException e) + { + isTrue("wrong message", "invalid KeySpec: point not on curve".equals(e.getMessage())); + } + catch (java.security.InvalidKeyException e) + { + isTrue("wrong message", "calculation failed: Invalid point".equals(e.getMessage())); + } } private void testDESAndDESede(BigInteger g, BigInteger p) throws Exception { - DHParameterSpec dhParams = new DHParameterSpec(p, g, 256); + DHParameterSpec dhParams = new DHParameterSpec(p, g, 256); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC"); @@ -791,13 +824,13 @@ DHPrivateKeySpec aPrivSpec = new DHPrivateKeySpec( new BigInteger("30a6ea4e2240a42867ad98bd3adbfd5b81aba48bd930f20a595983d807566f7cba4e766951efef2c6c0c1be3823f63d66e12c2a091d5ff3bbeb1ea6e335d072d", 16), p, g); DHPublicKeySpec aPubSpec = new DHPublicKeySpec( - new BigInteger("694dfea1bfc8897e2fcbfd88033ab34f4581892d7d5cc362dc056e3d43955accda12222bd651ca31c85f008a05dea914de68828dfd83a54a340fa84f3bbe6caf", 16), p, g); + new BigInteger("694dfea1bfc8897e2fcbfd88033ab34f4581892d7d5cc362dc056e3d43955accda12222bd651ca31c85f008a05dea914de68828dfd83a54a340fa84f3bbe6caf", 16), p, g); DHPrivateKeySpec bPrivSpec = new DHPrivateKeySpec( - new BigInteger("775b1e7e162190700e2212dd8e4aaacf8a2af92c9c108b81d5bf9a14548f494eaa86a6c4844b9512eb3e3f2f22ffec44c795c813edfea13f075b99bbdebb34bd", 16), p, g); + new BigInteger("775b1e7e162190700e2212dd8e4aaacf8a2af92c9c108b81d5bf9a14548f494eaa86a6c4844b9512eb3e3f2f22ffec44c795c813edfea13f075b99bbdebb34bd", 16), p, g); DHPublicKeySpec bPubSpec = new DHPublicKeySpec( - new BigInteger("d8ddd4ff9246635eadbfa0bc2ef06d98a329b6e8cd2d1435d7b4921467570e697c9a9d3c172c684626a9d2b6b2fa0fc725d5b91f9a9625b717a4169bc714b064", 16), p, g); + new BigInteger("d8ddd4ff9246635eadbfa0bc2ef06d98a329b6e8cd2d1435d7b4921467570e697c9a9d3c172c684626a9d2b6b2fa0fc725d5b91f9a9625b717a4169bc714b064", 16), p, g); KeyFactory kFact = KeyFactory.getInstance("DH", "BC"); @@ -817,7 +850,7 @@ private void testEnc() throws Exception { - KeyFactory kFact = KeyFactory.getInstance("DH", "BC"); + KeyFactory kFact = KeyFactory.getInstance("DH", "BC"); Key k = kFact.generatePrivate(new PKCS8EncodedKeySpec(samplePrivEnc)); @@ -858,9 +891,9 @@ 384); DHParameterSpec dhSpec768 = new DHParameterSpec( - new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d890141922d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d777d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", 16), - new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d83c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", 16), - 384); + new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d890141922d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d777d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", 16), + new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d83c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", 16), + 384); DHParameterSpec dhSpec1024 = new DHParameterSpec( new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16), @@ -879,7 +912,7 @@ fail("config found when none expected"); } - prov.setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, new DHParameterSpec[] { dhSpec512, dhSpec768, dhSpec1024 }); + prov.setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, new DHParameterSpec[]{dhSpec512, dhSpec768, dhSpec1024}); if (!dhSpec512.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(512))) { @@ -920,7 +953,7 @@ fail("config found when none expected"); } - prov.setParameter(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS, new DHParameterSpec[] { dhSpec512, dhSpec768, dhSpec1024 }); + prov.setParameter(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS, new DHParameterSpec[]{dhSpec512, dhSpec768, dhSpec1024}); if (!dhSpec512.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(512))) { @@ -950,6 +983,109 @@ } } + static final String MESSAGE = "Hello"; + + static final String PROVIDER_NAME = "BC"; + static final SecureRandom rand = new SecureRandom(); + + public void setUp() + { + // Add BouncyCastle for testing. + Security.insertProviderAt(new BouncyCastleProvider(), 1); + System.out.println("WARNING: Using BouncyCastleProvider"); + } + + public DHParameterSpec ike2048() + { + final BigInteger p = new BigInteger( + "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74" + + "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437" + + "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed" + + "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf05" + + "98da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb" + + "9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3b" + + "e39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf695581718" + + "3995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff", 16); + final BigInteger g = new BigInteger("2"); + return new DHParameterSpec(p, g); + } + + /** + * Tests whether a provider accepts invalid public keys that result in predictable shared secrets. + * This test is based on RFC 2785, Section 4 and NIST SP 800-56A, + * If an attacker can modify both public keys in an ephemeral-ephemeral key agreement scheme then + * it may be possible to coerce both parties into computing the same predictable shared key. + *

      + * Note: the test is quite whimsical. If the prime p is not a safe prime then the provider itself + * cannot prevent all small-subgroup attacks because of the missing parameter q in the + * Diffie-Hellman parameters. Implementations must add additional countermeasures such as the ones + * proposed in RFC 2785. + */ + private void testSubgroupConfinement() + throws Exception + { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC"); + DHParameterSpec params = ike2048(); + final BigInteger p = params.getP(); + final BigInteger g = params.getG(); + keyGen.initialize(params); + PrivateKey priv = keyGen.generateKeyPair().getPrivate(); + KeyAgreement ka = KeyAgreement.getInstance("DH", "BC"); + BigInteger[] weakPublicKeys = { + BigInteger.ZERO, BigInteger.ONE, p.subtract(BigInteger.ONE), p, + p.add(BigInteger.ONE), BigInteger.ONE.negate()}; + for (final BigInteger weakKey : weakPublicKeys) + { + DHPublicKeySpec weakSpec = new DHPublicKeySpec(weakKey, p, g); + KeyFactory kf = KeyFactory.getInstance("DH", "BC"); + try + { + kf.generatePublic(weakSpec); + fail("Generated weak public key"); + } + catch (GeneralSecurityException ex) + { + isTrue("wrong message (generate)", "invalid DH public key".equals(ex.getMessage())); + } + ka.init(priv); + try + { + ka.doPhase(new DHPublicKey() + { + public BigInteger getY() + { + return weakKey; + } + + public DHParameterSpec getParams() + { + return new DHParameterSpec(p, g); + } + + public String getAlgorithm() + { + return null; + } + + public String getFormat() + { + return null; + } + + public byte[] getEncoded() + { + return new byte[0]; + } + }, true); + fail("Generated secrets with weak public key"); + } + catch (GeneralSecurityException ex) + { + isTrue("wrong message (doPhase)", "Invalid DH PublicKey".equals(ex.getMessage())); + } + } + } + public void performTest() throws Exception { @@ -983,10 +1119,11 @@ testInitialise(); testSmallSecret(); testConfig(); + testSubgroupConfinement(); } public static void main( - String[] args) + String[] args) { Security.addProvider(new BouncyCastleProvider()); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java 2016-04-25 02:10:26.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java 2016-11-03 10:18:32.000000000 +0000 @@ -20,6 +20,7 @@ import java.security.Security; import java.security.Signature; import java.security.SignatureException; +import java.security.interfaces.DSAParams; import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.DSAPublicKey; import java.security.spec.DSAParameterSpec; @@ -38,6 +39,8 @@ import org.bouncycastle.asn1.nist.NISTNamedCurves; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.params.DSAParameters; @@ -57,6 +60,8 @@ import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomBigInteger; +import org.bouncycastle.util.test.TestRandomData; public class DSATest extends SimpleTest @@ -65,7 +70,112 @@ byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2 }); - + + // DSA modified signatures, courtesy of the Google security team + static final DSAPrivateKeySpec PRIVATE_KEY = new DSAPrivateKeySpec( + // x + new BigInteger( + "15382583218386677486843706921635237927801862255437148328980464126979"), + // p + new BigInteger( + "181118486631420055711787706248812146965913392568235070235446058914" + + "1170708161715231951918020125044061516370042605439640379530343556" + + "4101919053459832890139496933938670005799610981765220283775567361" + + "4836626483403394052203488713085936276470766894079318754834062443" + + "1033792580942743268186462355159813630244169054658542719322425431" + + "4088256212718983105131138772434658820375111735710449331518776858" + + "7867938758654181244292694091187568128410190746310049564097068770" + + "8161261634790060655580211122402292101772553741704724263582994973" + + "9109274666495826205002104010355456981211025738812433088757102520" + + "562459649777989718122219159982614304359"), + // q + new BigInteger( + "19689526866605154788513693571065914024068069442724893395618704484701"), + // g + new BigInteger( + "2859278237642201956931085611015389087970918161297522023542900348" + + "0877180630984239764282523693409675060100542360520959501692726128" + + "3149190229583566074777557293475747419473934711587072321756053067" + + "2532404847508798651915566434553729839971841903983916294692452760" + + "2490198571084091890169933809199002313226100830607842692992570749" + + "0504363602970812128803790973955960534785317485341020833424202774" + + "0275688698461842637641566056165699733710043802697192696426360843" + + "1736206792141319514001488556117408586108219135730880594044593648" + + "9237302749293603778933701187571075920849848690861126195402696457" + + "4111219599568903257472567764789616958430")); + + static final DSAPublicKeySpec PUBLIC_KEY = new DSAPublicKeySpec( + new BigInteger( + "3846308446317351758462473207111709291533523711306097971550086650" + + "2577333637930103311673872185522385807498738696446063139653693222" + + "3528823234976869516765207838304932337200968476150071617737755913" + + "3181601169463467065599372409821150709457431511200322947508290005" + + "1780020974429072640276810306302799924668893998032630777409440831" + + "4314588994475223696460940116068336991199969153649625334724122468" + + "7497038281983541563359385775312520539189474547346202842754393945" + + "8755803223951078082197762886933401284142487322057236814878262166" + + "5072306622943221607031324846468109901964841479558565694763440972" + + "5447389416166053148132419345627682740529"), + PRIVATE_KEY.getP(), + PRIVATE_KEY.getQ(), + PRIVATE_KEY.getG()); + + // The following test vectors check for signature malleability and bugs. That means the test + // vectors are derived from a valid signature by modifying the ASN encoding. A correct + // implementation of DSA should only accept correct DER encoding and properly handle the others. + // Allowing alternative BER encodings is in many cases benign. An example where this kind of + // signature malleability was a problem: https://en.bitcoin.it/wiki/Transaction_Malleability + static final String[] MODIFIED_SIGNATURES = { + "303e02811c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9e" + + "f41dd424a4e1c8f16967cf3365813fe8786236", + "303f0282001c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f" + + "9ef41dd424a4e1c8f16967cf3365813fe8786236", + "303e021d001e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9e" + + "f41dd424a4e1c8f16967cf3365813fe8786236", + "303e021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd02811d00ade65988d237d30f9e" + + "f41dd424a4e1c8f16967cf3365813fe8786236", + "303f021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd0282001d00ade65988d237d30f" + + "9ef41dd424a4e1c8f16967cf3365813fe8786236", + "303e021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021e0000ade65988d237d30f9e" + + "f41dd424a4e1c8f16967cf3365813fe8786236", + "30813d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9e" + + "f41dd424a4e1c8f16967cf3365813fe8786236", + "3082003d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f" + + "9ef41dd424a4e1c8f16967cf3365813fe8786236", + "303d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9ef4" + + "1dd424a4e1c8f16967cf3365813fe87862360000", + "3040021c57b10411b54ab248af03d8f2456676ebc6d3db5f1081492ac87e9ca8021d00942b117051d7d9d107fc42cac9c5a36a1fd7f0f8916ccca86cec4ed3040100", + "303e021c57b10411b54ab248af03d8f2456676ebc6d3db5f1081492ac87e9ca802811d00942b117051d7d9d107fc42cac9c5a36a1fd7f0f8916ccca86cec4ed3" + }; + + private void testModified() + throws Exception + { + KeyFactory kFact = KeyFactory.getInstance("DSA", "BC"); + PublicKey pubKey = kFact.generatePublic(PUBLIC_KEY); + Signature sig = Signature.getInstance("DSA", "BC"); + + for (int i = 0; i != MODIFIED_SIGNATURES.length; i++) + { + sig.initVerify(pubKey); + + sig.update(Strings.toByteArray("Hello")); + + boolean failed; + + try + { + failed = !sig.verify(Hex.decode(MODIFIED_SIGNATURES[i])); + } + catch (SignatureException e) + { + failed = true; + } + + isTrue("sig verified when shouldn't", failed); + } + } + private void testCompat() throws Exception { @@ -158,6 +268,66 @@ checkPrivateKey(k2, sKey); } + private void testNullParameters() + throws Exception + { + KeyFactory f = KeyFactory.getInstance("DSA", "BC"); + X509EncodedKeySpec x509s = new X509EncodedKeySpec(new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new ASN1Integer(10001)).getEncoded()); + + DSAPublicKey key1 = (DSAPublicKey)f.generatePublic(x509s); + DSAPublicKey key2 = (DSAPublicKey)f.generatePublic(x509s); + + isTrue("parameters not absent", key1.getParams() == null && key2.getParams() == null); + isTrue("hashCode mismatch", key1.hashCode() == key2.hashCode()); + isTrue("not equal", key1.equals(key2)); + isTrue("encoding mismatch", Arrays.areEqual(x509s.getEncoded(), key1.getEncoded())); + } + + private void testValidate() + throws Exception + { + DSAParameterSpec dsaParams = new DSAParameterSpec( + new BigInteger( + "F56C2A7D366E3EBDEAA1891FD2A0D099" + + "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" + + "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" + + "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" + + "5909132627F51A0C866877E672E555342BDF9355347DBD43" + + "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" + + "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" + + "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" + + "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" + + "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" + + "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16), + new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16), + new BigInteger( + "8DC6CC814CAE4A1C05A3E186A6FE27EA" + + "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" + + "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" + + "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" + + "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" + + "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" + + "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" + + "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" + + "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" + + "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" + + "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16) + ); + + KeyFactory f = KeyFactory.getInstance("DSA", "BC"); + + try + { + f.generatePublic(new DSAPublicKeySpec(BigInteger.valueOf(1), dsaParams.getP(), dsaParams.getG(), dsaParams.getQ())); + + fail("no exception"); + } + catch (Exception e) + { + isTrue("mismatch", "invalid KeySpec: y value does not appear to be in correct group".equals(e.getMessage())); + } + } + private void testNONEwithDSA() throws Exception { @@ -280,7 +450,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); ECCurve curve = new ECCurve.Fp( new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q @@ -413,7 +583,7 @@ private void doEcDsaTest(String sigName, BigInteger s, KeyFactory ecKeyFact, ECPublicKeySpec pubKey, ECPrivateKeySpec priKey) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, InvalidKeySpecException, SignatureException { - SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); @@ -517,7 +687,9 @@ private void doDsaTest(String sigName, BigInteger s, KeyFactory ecKeyFact, DSAPublicKeySpec pubKey, DSAPrivateKeySpec priKey) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, InvalidKeySpecException, SignatureException { - SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); + SecureRandom k = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))), + new FixedSecureRandom.Data(Hex.decode("01020304")) }); byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); @@ -565,7 +737,7 @@ { byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); sgr.initSign(sKey, k); @@ -601,7 +773,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); ECCurve curve = new ECCurve.F2m( 239, // m @@ -666,7 +838,7 @@ { byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); ECCurve curve = new ECCurve.F2m( 239, // m @@ -1061,7 +1233,7 @@ } KeyPairGenerator g = KeyPairGenerator.getInstance("DSA", "BC"); - g.initialize(dsaP, new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C"))); + g.initialize(dsaP, new TestRandomBigInteger(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C"))); KeyPair p = g.generateKeyPair(); DSAPrivateKey sKey = (DSAPrivateKey)p.getPrivate(); @@ -1123,6 +1295,51 @@ } } + private void testKeyGeneration(int keysize) + throws Exception + { + KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA", "BC"); + generator.initialize(keysize); + KeyPair keyPair = generator.generateKeyPair(); + DSAPrivateKey priv = (DSAPrivateKey)keyPair.getPrivate(); + DSAParams params = priv.getParams(); + isTrue("keysize mismatch", keysize == params.getP().bitLength()); + // The NIST standard does not fully specify the size of q that + // must be used for a given key size. Hence there are differences. + // For example if keysize = 2048, then OpenSSL uses 256 bit q's by default, + // but the SUN provider uses 224 bits. Both are acceptable sizes. + // The tests below simply asserts that the size of q does not decrease the + // overall security of the DSA. + int qsize = params.getQ().bitLength(); + switch (keysize) + { + case 1024: + isTrue("Invalid qsize for 1024 bit key:" + qsize, qsize >= 160); + break; + case 2048: + isTrue("Invalid qsize for 2048 bit key:" + qsize, qsize >= 224); + break; + case 3072: + isTrue("Invalid qsize for 3072 bit key:" + qsize, qsize >= 256); + break; + default: + fail("Invalid key size:" + keysize); + } + // Check the length of the private key. + // For example GPG4Browsers or the KJUR library derived from it use + // q.bitCount() instead of q.bitLength() to determine the size of the private key + // and hence would generate keys that are much too small. + isTrue("privkey error", priv.getX().bitLength() >= qsize - 32); + } + + private void testKeyGenerationAll() + throws Exception + { + testKeyGeneration(1024); + testKeyGeneration(2048); + testKeyGeneration(3072); + } + public void performTest() throws Exception { @@ -1157,6 +1374,10 @@ testGeneration(); testParameters(); testDSA2Parameters(); + testNullParameters(); + testValidate(); + testModified(); + testKeyGenerationAll(); } protected BigInteger[] derDecode( @@ -1189,7 +1410,7 @@ } private class DSATestSecureRandom - extends FixedSecureRandom + extends TestRandomData { private boolean first = true; diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java 2015-06-07 11:13:20.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java 2016-09-29 23:44:55.000000000 +0000 @@ -2,20 +2,14 @@ import java.io.IOException; import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.Signature; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -25,8 +19,8 @@ import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomBigInteger; public class DSTU4145Test extends SimpleTest @@ -65,8 +59,8 @@ curve.createPoint(new BigInteger("BE6628EC3E67A91A4E470894FBA72B52C515F8AEE9", 16), new BigInteger("D9DEEDF655CF5412313C11CA566CDC71F4DA57DB45C", 16), false), new BigInteger("800000000000000000000189B4E67606E3825BB2831", 16)); - SecureRandom k = new FixedSecureRandom(Hex.decode("00137449348C1249971759D99C252FFE1E14D8B31F00")); - SecureRandom keyRand = new FixedSecureRandom(Hex.decode("0000955CD7E344303D1034E66933DC21C8044D42ADB8")); + SecureRandom k = new TestRandomBigInteger(Hex.decode("00137449348C1249971759D99C252FFE1E14D8B31F00")); + SecureRandom keyRand = new TestRandomBigInteger(Hex.decode("0000955CD7E344303D1034E66933DC21C8044D42ADB8")); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSTU4145", "BC"); keyGen.initialize(spec, keyRand); @@ -114,7 +108,7 @@ throws Exception { - SecureRandom k = new FixedSecureRandom(Hex.decode("00137449348C1249971759D99C252FFE1E14D8B31F00")); + SecureRandom k = new TestRandomBigInteger(Hex.decode("00137449348C1249971759D99C252FFE1E14D8B31F00")); ECCurve.F2m curve = new ECCurve.F2m(173, 1, 2, 10, BigInteger.ZERO, new BigInteger("108576C80499DB2FC16EDDF6853BBB278F6B6FB437D9", 16)); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ECDSA5Test.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ECDSA5Test.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ECDSA5Test.java 2015-09-22 06:38:29.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ECDSA5Test.java 2016-10-15 01:09:51.000000000 +0000 @@ -58,6 +58,7 @@ import org.bouncycastle.jce.ECNamedCurveTable; import org.bouncycastle.jce.ECPointUtil; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.BigIntegers; @@ -65,6 +66,7 @@ import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomBigInteger; public class ECDSA5Test extends SimpleTest @@ -72,14 +74,102 @@ byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); - SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2 }); - + SecureRandom random = new FixedSecureRandom( + new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2)}); + static final BigInteger PubX = + new BigInteger("3390396496586153202365024500890309020181905168626402195853036609" + + "0984128098564"); + static final BigInteger PubY = + new BigInteger("1135421298983937257390683162600855221890652900790509030911087400" + + "65052129055287"); + static final String[] VALID_SIGNATURES = { + "3045022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49" + + "1b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f94e418c106a6e76285" + + "cd59f43260ecce", + }; + + // The following test vectors check for signature malleability and bugs. That means the test + // vectors are derived from a valid signature by modifying the ASN encoding. A correct + // implementation of ECDSA should only accept correct DER encoding and properly handle the + // others (e.g. integer overflow, infinity, redundant parameters, etc). Allowing alternative BER + // encodings is in many cases benign. An example where this kind of signature malleability was a + // problem: https://en.bitcoin.it/wiki/Transaction_Malleability + static final String[] MODIFIED_SIGNATURES = { + "304602812100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f" + + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "30470282002100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd" + + "2f3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "304602220000b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f" + + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "3046022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f028120747291dd2f" + + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f02820020747291dd" + + "2f3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "3046022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f022100747291dd2f" + + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "308145022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f" + + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "30820045022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd" + + "2f3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce3000", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce1000", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0000", + "3045022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0000", + "3048022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce058100", + "3049022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce05820000", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce1100", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0500", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce2500", + "3067022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0220747291dd2f3f44af7ace68ea33431d6f" + + "94e418c106a6e76285cd59f43260ecce" + }; + + private void testModified() + throws Exception + { + ECNamedCurveParameterSpec namedCurve = ECNamedCurveTable.getParameterSpec("P-256"); + org.bouncycastle.jce.spec.ECPublicKeySpec pubSpec = new org.bouncycastle.jce.spec.ECPublicKeySpec(namedCurve.getCurve().createPoint(PubX, PubY), namedCurve); + KeyFactory kFact = KeyFactory.getInstance("EC", "BC"); + PublicKey pubKey = kFact.generatePublic(pubSpec); + Signature sig = Signature.getInstance("SHA256WithECDSA", "BC"); + + for (int i = 0; i != MODIFIED_SIGNATURES.length; i++) + { + sig.initVerify(pubKey); + + sig.update(Strings.toByteArray("Hello")); + + boolean failed; + + try + { + failed = !sig.verify(Hex.decode(MODIFIED_SIGNATURES[i])); + } + catch (SignatureException e) + { + failed = true; + } + + isTrue("sig verified when shouldn't: " + i, failed); + } + } + private void decodeTest() { EllipticCurve curve = new EllipticCurve( - new ECFieldFp(new BigInteger("6277101735386680763835789423207666416083908700390324961279")), // q - new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a - new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b + new ECFieldFp(new BigInteger("6277101735386680763835789423207666416083908700390324961279")), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b ECPoint p = ECPointUtil.decodePoint(curve, Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")); @@ -107,7 +197,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); EllipticCurve curve = new EllipticCurve( new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q @@ -119,7 +209,7 @@ ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n 1); // h - + ECPrivateKeySpec priKey = new ECPrivateKeySpec( new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d @@ -129,18 +219,18 @@ ECPointUtil.decodePoint(curve, Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q spec); - Signature sgr = Signature.getInstance("ECDSA", "BC"); - KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); - PrivateKey sKey = f.generatePrivate(priKey); - PublicKey vKey = f.generatePublic(pubKey); + Signature sgr = Signature.getInstance("ECDSA", "BC"); + KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); + PrivateKey sKey = f.generatePrivate(priKey); + PublicKey vKey = f.generatePublic(pubKey); sgr.initSign(sKey, k); - byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; + byte[] message = new byte[]{(byte)'a', (byte)'b', (byte)'c'}; sgr.update(message); - byte[] sigBytes = sgr.sign(); + byte[] sigBytes = sgr.sign(); sgr.initVerify(vKey); @@ -151,7 +241,7 @@ fail("239 Bit EC verification failed"); } - BigInteger[] sig = derDecode(sigBytes); + BigInteger[] sig = derDecode(sigBytes); if (!r.equals(sig[0])) { @@ -179,21 +269,21 @@ KeyPair kp = kpGen.generateKeyPair(); byte[] data = "Hello World!!!".getBytes(); - String[] cvcAlgs = { "SHA1WITHCVC-ECDSA", "SHA224WITHCVC-ECDSA", - "SHA256WITHCVC-ECDSA", "SHA384WITHCVC-ECDSA", - "SHA512WITHCVC-ECDSA" }; - String[] cvcOids = { EACObjectIdentifiers.id_TA_ECDSA_SHA_1.getId(), EACObjectIdentifiers.id_TA_ECDSA_SHA_224.getId(), - EACObjectIdentifiers.id_TA_ECDSA_SHA_256.getId(), EACObjectIdentifiers.id_TA_ECDSA_SHA_384.getId(), - EACObjectIdentifiers.id_TA_ECDSA_SHA_512.getId() }; + String[] cvcAlgs = {"SHA1WITHCVC-ECDSA", "SHA224WITHCVC-ECDSA", + "SHA256WITHCVC-ECDSA", "SHA384WITHCVC-ECDSA", + "SHA512WITHCVC-ECDSA"}; + String[] cvcOids = {EACObjectIdentifiers.id_TA_ECDSA_SHA_1.getId(), EACObjectIdentifiers.id_TA_ECDSA_SHA_224.getId(), + EACObjectIdentifiers.id_TA_ECDSA_SHA_256.getId(), EACObjectIdentifiers.id_TA_ECDSA_SHA_384.getId(), + EACObjectIdentifiers.id_TA_ECDSA_SHA_512.getId()}; testBsiAlgorithms(kp, data, cvcAlgs, cvcOids); - String[] plainAlgs = { "SHA1WITHPLAIN-ECDSA", "SHA224WITHPLAIN-ECDSA", - "SHA256WITHPLAIN-ECDSA", "SHA384WITHPLAIN-ECDSA", - "SHA512WITHPLAIN-ECDSA", "RIPEMD160WITHPLAIN-ECDSA" }; - String[] plainOids = { BSIObjectIdentifiers.ecdsa_plain_SHA1.getId(), BSIObjectIdentifiers.ecdsa_plain_SHA224.getId(), - BSIObjectIdentifiers.ecdsa_plain_SHA256.getId(), BSIObjectIdentifiers.ecdsa_plain_SHA384.getId(), - BSIObjectIdentifiers.ecdsa_plain_SHA512.getId(), BSIObjectIdentifiers.ecdsa_plain_RIPEMD160.getId() }; + String[] plainAlgs = {"SHA1WITHPLAIN-ECDSA", "SHA224WITHPLAIN-ECDSA", + "SHA256WITHPLAIN-ECDSA", "SHA384WITHPLAIN-ECDSA", + "SHA512WITHPLAIN-ECDSA", "RIPEMD160WITHPLAIN-ECDSA"}; + String[] plainOids = {BSIObjectIdentifiers.ecdsa_plain_SHA1.getId(), BSIObjectIdentifiers.ecdsa_plain_SHA224.getId(), + BSIObjectIdentifiers.ecdsa_plain_SHA256.getId(), BSIObjectIdentifiers.ecdsa_plain_SHA384.getId(), + BSIObjectIdentifiers.ecdsa_plain_SHA512.getId(), BSIObjectIdentifiers.ecdsa_plain_RIPEMD160.getId()}; testBsiAlgorithms(kp, data, plainAlgs, plainOids); } @@ -233,42 +323,42 @@ { BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552"); BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174"); - + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); EllipticCurve curve = new EllipticCurve( new ECFieldF2m(239, // m - new int[] { 36 }), // k + new int[]{36}), // k new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b - + ECParameterSpec params = new ECParameterSpec( curve, ECPointUtil.decodePoint(curve, Hex.decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n 4); // h - + ECPrivateKeySpec priKeySpec = new ECPrivateKeySpec( new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d params); - + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec( ECPointUtil.decodePoint(curve, Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q params); - - Signature sgr = Signature.getInstance("ECDSA", "BC"); - KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); - PrivateKey sKey = f.generatePrivate(priKeySpec); - PublicKey vKey = f.generatePublic(pubKeySpec); - byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; - + + Signature sgr = Signature.getInstance("ECDSA", "BC"); + KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); + PrivateKey sKey = f.generatePrivate(priKeySpec); + PublicKey vKey = f.generatePublic(pubKeySpec); + byte[] message = new byte[]{(byte)'a', (byte)'b', (byte)'c'}; + sgr.initSign(sKey, k); sgr.update(message); - - byte[] sigBytes = sgr.sign(); + + byte[] sigBytes = sgr.sign(); sgr.initVerify(vKey); @@ -279,7 +369,7 @@ fail("239 Bit EC verification failed"); } - BigInteger[] sig = derDecode(sigBytes); + BigInteger[] sig = derDecode(sigBytes); if (!r.equals(sig[0])) { @@ -295,14 +385,14 @@ + " got : " + sig[1]); } } - + private void testGeneration() throws Exception { // // ECDSA generation test // - byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; Signature s = Signature.getInstance("ECDSA", "BC"); KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); @@ -322,7 +412,7 @@ KeyPair p = g.generateKeyPair(); PrivateKey sKey = p.getPrivate(); - PublicKey vKey = p.getPublic(); + PublicKey vKey = p.getPublic(); s.initSign(sKey); @@ -376,8 +466,8 @@ { KeyFactory ecFact = KeyFactory.getInstance("ECDSA"); - ECPublicKeySpec pubSpec = (ECPublicKeySpec)ecFact.getKeySpec(pub, ECPublicKeySpec.class); - ECPrivateKeySpec privSpec = (ECPrivateKeySpec)ecFact.getKeySpec(priv, ECPrivateKeySpec.class); + ECPublicKeySpec pubSpec = (ECPublicKeySpec)ecFact.getKeySpec(pub, ECPublicKeySpec.class); + ECPrivateKeySpec privSpec = (ECPrivateKeySpec)ecFact.getKeySpec(priv, ECPrivateKeySpec.class); if (!pubSpec.getW().equals(pub.getW()) || !pubSpec.getParams().getCurve().equals(pub.getParams().getCurve())) { @@ -389,8 +479,8 @@ fail("privSpec not correct"); } - ECPublicKey pubKey = (ECPublicKey)ecFact.translateKey(pub); - ECPrivateKey privKey = (ECPrivateKey)ecFact.translateKey(priv); + ECPublicKey pubKey = (ECPublicKey)ecFact.translateKey(pub); + ECPrivateKey privKey = (ECPrivateKey)ecFact.translateKey(priv); if (!pubKey.getW().equals(pub.getW()) || !pubKey.getParams().getCurve().equals(pub.getParams().getCurve())) { @@ -452,7 +542,7 @@ KeyPair pair = kpGen.generateKeyPair(); final PrivateKey privKey = pair.getPrivate(); - final PublicKey pubKey = pair.getPublic(); + final PublicKey pubKey = pair.getPublic(); Signature s = Signature.getInstance("ECDSA", "BC"); @@ -667,7 +757,7 @@ pair = kpGen.generateKeyPair(); final PrivateKey privRsa = pair.getPrivate(); - final PublicKey pubRsa = pair.getPublic(); + final PublicKey pubRsa = pair.getPublic(); try { @@ -925,24 +1015,24 @@ } /** - COUNT = 1 - dsCAVS = 00000179557decd75b797bea9db656ce99c03a6e0ab13804b5b589644f7db41ceba05c3940c300361061074ca72a828428d9198267fa0b75e1e3e785a0ff20e839414be0 - QsCAVSx = 000001ce7da31681d5f176f3618f205969b9142520363dd26a596866c89988c932e3ce01904d12d1e9b105462e56163dbe7658ba3c472bf1f3c8165813295393ae346764 - QsCAVSy = 000000e70d6e55b76ebd362ff071ab819315593cec650276209a9fdc2c1c48e03c35945f04e74d958cabd3f5e4d1f096a991e807a8f9d217de306a6b561038ca15aea4b9 - NonceEphemCAVS = 4214a1a0a1d11679ae22f98d7ae483c1a74008a9cd7f7cf71b1f373a4226f5c58eb621ec56e2537797c01750dcbff07f613b9c58774f9af32aebeadd2226140dc7d56b1aa95c93ab1ec4412e2d0e42cdaac7bf9da3ddbf19fbb1edd0556d9c5a339808905fe8defd8b57ff8f34788192cc0cf7df17d1f351d69ac979a3a495931c287fb8 - dsIUT = 000000c14895dfcc5a6b24994828cfd0a0cc0a881a70173a3eb05c57b098046c8e60a868f6176284aa346eff1fd1b8b879052c5a6d5fd0ae146b35ed7ecee32e294103cd - QsIUTx = 00000174a658695049db59f6bbe2ad23e1753bf58384a56fc9b3dec13eb873b33e1f4dbd24b6b4ca05a9a11ad531f6d99e9430a774980e8a8d9fd2d1e2a0d76fe3dd36c7 - QsIUTy = 00000030639849e1df341973db44e7bbba5bb597884a439f9ce54620c3ca73a9804cc26fcda3aaf73ae5a11d5b325cae0e95cfafe1985c6c2fdb892722e7dd2c5d744cf3 - deIUT = 00000138f54e986c7b44f49da389fa9f61bb7265f0cebdeddf09d47c72e55186e2520965fc2c31bb9c0a557e3c28e02a751f097e413c4252c7b0d22452d89f9ac314bc6e - QeIUTx = 000001b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf01120 - QeIUTy = 000000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a - OI = a1b2c3d4e54341565369646dbb63a273c81e0aad02f92699bf7baa28fd4509145b0096746894e98e209a85ecb415b8 - CAVSTag = 4ade5dc983cc1cf61c90fdbf726fa6a88e9bf411bbaf0015db06ff4348560e4d - Z = 019a19a0a99f60221ee23323b3317292e8c10d57ba04e0b33f6241979ec3895945eed0bdcbc59ab576e7047061f0d63d1aaf78b1d442028605aa1c0f963a3bc9d61a - MacData = 4b435f315f55a1b2c3d4e543415653696401b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf0112000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a4214a1a0a1d11679ae22f98d7ae483c1a74008a9cd7f7cf71b1f373a4226f5c58eb621ec56e2537797c01750dcbff07f613b9c58774f9af32aebeadd2226140dc7d56b1aa95c93ab1ec4412e2d0e42cdaac7bf9da3ddbf19fbb1edd0556d9c5a339808905fe8defd8b57ff8f34788192cc0cf7df17d1f351d69ac979a3a495931c287fb8 - DKM = 0744e1774149a8b8f88d3a1e20ac1517efd2f54ba4b5f178de99f33b68eea426 - Result = P (14 - DKM value should have leading 0 nibble ) - */ + * COUNT = 1 + * dsCAVS = 00000179557decd75b797bea9db656ce99c03a6e0ab13804b5b589644f7db41ceba05c3940c300361061074ca72a828428d9198267fa0b75e1e3e785a0ff20e839414be0 + * QsCAVSx = 000001ce7da31681d5f176f3618f205969b9142520363dd26a596866c89988c932e3ce01904d12d1e9b105462e56163dbe7658ba3c472bf1f3c8165813295393ae346764 + * QsCAVSy = 000000e70d6e55b76ebd362ff071ab819315593cec650276209a9fdc2c1c48e03c35945f04e74d958cabd3f5e4d1f096a991e807a8f9d217de306a6b561038ca15aea4b9 + * NonceEphemCAVS = 4214a1a0a1d11679ae22f98d7ae483c1a74008a9cd7f7cf71b1f373a4226f5c58eb621ec56e2537797c01750dcbff07f613b9c58774f9af32aebeadd2226140dc7d56b1aa95c93ab1ec4412e2d0e42cdaac7bf9da3ddbf19fbb1edd0556d9c5a339808905fe8defd8b57ff8f34788192cc0cf7df17d1f351d69ac979a3a495931c287fb8 + * dsIUT = 000000c14895dfcc5a6b24994828cfd0a0cc0a881a70173a3eb05c57b098046c8e60a868f6176284aa346eff1fd1b8b879052c5a6d5fd0ae146b35ed7ecee32e294103cd + * QsIUTx = 00000174a658695049db59f6bbe2ad23e1753bf58384a56fc9b3dec13eb873b33e1f4dbd24b6b4ca05a9a11ad531f6d99e9430a774980e8a8d9fd2d1e2a0d76fe3dd36c7 + * QsIUTy = 00000030639849e1df341973db44e7bbba5bb597884a439f9ce54620c3ca73a9804cc26fcda3aaf73ae5a11d5b325cae0e95cfafe1985c6c2fdb892722e7dd2c5d744cf3 + * deIUT = 00000138f54e986c7b44f49da389fa9f61bb7265f0cebdeddf09d47c72e55186e2520965fc2c31bb9c0a557e3c28e02a751f097e413c4252c7b0d22452d89f9ac314bc6e + * QeIUTx = 000001b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf01120 + * QeIUTy = 000000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a + * OI = a1b2c3d4e54341565369646dbb63a273c81e0aad02f92699bf7baa28fd4509145b0096746894e98e209a85ecb415b8 + * CAVSTag = 4ade5dc983cc1cf61c90fdbf726fa6a88e9bf411bbaf0015db06ff4348560e4d + * Z = 019a19a0a99f60221ee23323b3317292e8c10d57ba04e0b33f6241979ec3895945eed0bdcbc59ab576e7047061f0d63d1aaf78b1d442028605aa1c0f963a3bc9d61a + * MacData = 4b435f315f55a1b2c3d4e543415653696401b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf0112000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a4214a1a0a1d11679ae22f98d7ae483c1a74008a9cd7f7cf71b1f373a4226f5c58eb621ec56e2537797c01750dcbff07f613b9c58774f9af32aebeadd2226140dc7d56b1aa95c93ab1ec4412e2d0e42cdaac7bf9da3ddbf19fbb1edd0556d9c5a339808905fe8defd8b57ff8f34788192cc0cf7df17d1f351d69ac979a3a495931c287fb8 + * DKM = 0744e1774149a8b8f88d3a1e20ac1517efd2f54ba4b5f178de99f33b68eea426 + * Result = P (14 - DKM value should have leading 0 nibble ) + */ public void testMQVwithHMACOnePass() throws Exception { @@ -954,17 +1044,17 @@ KeyFactory keyFact = KeyFactory.getInstance("EC", "BC"); ECPrivateKey dsCAVS = (ECPrivateKey)keyFact.generatePrivate(new ECPrivateKeySpec(new BigInteger("00000179557decd75b797bea9db656ce99c03a6e0ab13804b5b589644f7db41ceba05c3940c300361061074ca72a828428d9198267fa0b75e1e3e785a0ff20e839414be0", 16), ecSpec)); - ECPublicKey qsCAVS = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint( - new BigInteger("000001ce7da31681d5f176f3618f205969b9142520363dd26a596866c89988c932e3ce01904d12d1e9b105462e56163dbe7658ba3c472bf1f3c8165813295393ae346764", 16), - new BigInteger("000000e70d6e55b76ebd362ff071ab819315593cec650276209a9fdc2c1c48e03c35945f04e74d958cabd3f5e4d1f096a991e807a8f9d217de306a6b561038ca15aea4b9", 16)), ecSpec)); + ECPublicKey qsCAVS = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint( + new BigInteger("000001ce7da31681d5f176f3618f205969b9142520363dd26a596866c89988c932e3ce01904d12d1e9b105462e56163dbe7658ba3c472bf1f3c8165813295393ae346764", 16), + new BigInteger("000000e70d6e55b76ebd362ff071ab819315593cec650276209a9fdc2c1c48e03c35945f04e74d958cabd3f5e4d1f096a991e807a8f9d217de306a6b561038ca15aea4b9", 16)), ecSpec)); ECPrivateKey dsIUT = (ECPrivateKey)keyFact.generatePrivate(new ECPrivateKeySpec(new BigInteger("000000c14895dfcc5a6b24994828cfd0a0cc0a881a70173a3eb05c57b098046c8e60a868f6176284aa346eff1fd1b8b879052c5a6d5fd0ae146b35ed7ecee32e294103cd", 16), ecSpec)); - ECPublicKey qsIUT = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint( - new BigInteger("00000174a658695049db59f6bbe2ad23e1753bf58384a56fc9b3dec13eb873b33e1f4dbd24b6b4ca05a9a11ad531f6d99e9430a774980e8a8d9fd2d1e2a0d76fe3dd36c7", 16), - new BigInteger("00000030639849e1df341973db44e7bbba5bb597884a439f9ce54620c3ca73a9804cc26fcda3aaf73ae5a11d5b325cae0e95cfafe1985c6c2fdb892722e7dd2c5d744cf3", 16)), ecSpec)); + ECPublicKey qsIUT = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint( + new BigInteger("00000174a658695049db59f6bbe2ad23e1753bf58384a56fc9b3dec13eb873b33e1f4dbd24b6b4ca05a9a11ad531f6d99e9430a774980e8a8d9fd2d1e2a0d76fe3dd36c7", 16), + new BigInteger("00000030639849e1df341973db44e7bbba5bb597884a439f9ce54620c3ca73a9804cc26fcda3aaf73ae5a11d5b325cae0e95cfafe1985c6c2fdb892722e7dd2c5d744cf3", 16)), ecSpec)); ECPrivateKey deIUT = (ECPrivateKey)keyFact.generatePrivate(new ECPrivateKeySpec(new BigInteger("00000138f54e986c7b44f49da389fa9f61bb7265f0cebdeddf09d47c72e55186e2520965fc2c31bb9c0a557e3c28e02a751f097e413c4252c7b0d22452d89f9ac314bc6e", 16), ecSpec)); - ECPublicKey qeIUT = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint( + ECPublicKey qeIUT = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint( new BigInteger("000001b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf01120", 16), new BigInteger("000000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a", 16)), ecSpec)); @@ -997,14 +1087,14 @@ } protected BigInteger[] derDecode( - byte[] encoding) + byte[] encoding) throws IOException { - ByteArrayInputStream bIn = new ByteArrayInputStream(encoding); - ASN1InputStream aIn = new ASN1InputStream(bIn); - ASN1Sequence s = (ASN1Sequence)aIn.readObject(); + ByteArrayInputStream bIn = new ByteArrayInputStream(encoding); + ASN1InputStream aIn = new ASN1InputStream(bIn); + ASN1Sequence s = (ASN1Sequence)aIn.readObject(); - BigInteger[] sig = new BigInteger[2]; + BigInteger[] sig = new BigInteger[2]; sig[0] = ((ASN1Integer)s.getObjectAt(0)).getValue(); sig[1] = ((ASN1Integer)s.getObjectAt(1)).getValue(); @@ -1032,10 +1122,11 @@ testBSI(); testMQVwithHMACOnePass(); testAlgorithmParameters(); + testModified(); } public static void main( - String[] args) + String[] args) { Security.addProvider(new BouncyCastleProvider()); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ECIESTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ECIESTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ECIESTest.java 2016-02-24 12:04:09.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ECIESTest.java 2016-08-27 03:11:44.000000000 +0000 @@ -7,6 +7,7 @@ import java.security.Security; import java.security.spec.ECGenParameterSpec; +import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.SealedObject; @@ -22,6 +23,7 @@ import org.bouncycastle.jce.interfaces.ECPublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.IESParameterSpec; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; @@ -75,19 +77,10 @@ new HMac(new SHA1Digest()), new PaddedBufferedBlockCipher(new DESEngine()))); - params = new IESParameterSpec(derivation, encoding, 128, 128); + params = new IESParameterSpec(derivation, encoding, 128, 128, Hex.decode("0001020304050607")); // Testing ECIES with default curve using DES g = KeyPairGenerator.getInstance("EC", "BC"); - doTest("default", g, "ECIESwithDESEDE", params); - - // Testing ECIES with 192-bit curve using DES - g.initialize(192, new SecureRandom()); - doTest("192-bit", g, "ECIESwithDESEDE", params); - - // Testing ECIES with 256-bit curve using DES - g.initialize(256, new SecureRandom()); - doTest("256-bit", g, "ECIESwithDESEDE", params); // Testing ECIES with 256-bit curve using DES-CBC g.initialize(256, new SecureRandom()); @@ -112,21 +105,9 @@ } } - c1 = new org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIESwithAES(); - c2 = new org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIESwithAES(); - params = new IESParameterSpec(derivation, encoding, 128, 128); - - // Testing ECIES with default curve using AES - g = KeyPairGenerator.getInstance("EC", "BC"); - doTest("default", g, "ECIESwithAES", params); - - // Testing ECIES with 192-bit curve using AES - g.initialize(192, new SecureRandom()); - doTest("192-bit", g, "ECIESwithAES", params); - - // Testing ECIES with 256-bit curve using AES - g.initialize(256, new SecureRandom()); - doTest("256-bit", g, "ECIESwithAES", params); + c1 = new org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIESwithAESCBC(); + c2 = new org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIESwithAESCBC(); + params = new IESParameterSpec(derivation, encoding, 128, 128, Hex.decode("000102030405060708090a0b0c0d0e0f")); // Testing ECIES with 256-bit curve using AES-CBC g.initialize(256, new SecureRandom()); @@ -151,6 +132,45 @@ } } + KeyPair keyPair = g.generateKeyPair(); + ECPublicKey pub = (ECPublicKey)keyPair.getPublic(); + ECPrivateKey priv = (ECPrivateKey)keyPair.getPrivate(); + + Cipher c = Cipher.getInstance("ECIESwithAES-CBC", "BC"); + + try + { + c.init(Cipher.ENCRYPT_MODE, pub, new IESParameterSpec(derivation, encoding, 128, 128, null)); + + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } + + try + { + c.init(Cipher.DECRYPT_MODE, priv); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isTrue("message ", "cannot handle supplied parameter spec: NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } + + try + { + c.init(Cipher.DECRYPT_MODE, priv, new IESParameterSpec(derivation, encoding, 128, 128, null)); + + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } + sealedObjectTest(); } @@ -204,7 +224,10 @@ // Testing with null parameters and DHAES mode off c1.init(Cipher.ENCRYPT_MODE, Pub, new SecureRandom()); - c2.init(Cipher.DECRYPT_MODE, Priv, new SecureRandom()); + c2.init(Cipher.DECRYPT_MODE, Priv, c1.getParameters()); + + isTrue("nonce mismatch", Arrays.areEqual(c1.getIV(), c2.getIV())); + out1 = c1.doFinal(message, 0, message.length); out2 = c2.doFinal(out1, 0, out1.length); if (!areEqual(out2, message)) @@ -213,13 +236,33 @@ // Testing with given parameters and DHAES mode off c1.init(Cipher.ENCRYPT_MODE, Pub, p, new SecureRandom()); - c2.init(Cipher.DECRYPT_MODE, Priv, p, new SecureRandom()); + c2.init(Cipher.DECRYPT_MODE, Priv, p); out1 = c1.doFinal(message, 0, message.length); out2 = c2.doFinal(out1, 0, out1.length); if (!areEqual(out2, message)) fail(testname + " test failed with non-null parameters, DHAES mode false."); + // + // corrupted data test + // + int offset = out1.length - (message.length + 8); + byte[] tmp = new byte[out1.length]; + for (int i = offset; i != out1.length; i++) + { + System.arraycopy(out1, 0, tmp, 0, tmp.length); + tmp[i] = (byte)~tmp[i]; + try + { + c2.doFinal(tmp, 0, tmp.length); + + fail("decrypted corrupted data"); + } + catch (BadPaddingException e) + { + isTrue("wrong message: " + e.getMessage(), "unable to process block".equals(e.getMessage())); + } + } // TODO: DHAES mode is not currently implemented, perhaps it shouldn't be... // c1 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC"); // c2 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC"); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ECIESVectorTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ECIESVectorTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ECIESVectorTest.java 2015-07-17 00:13:45.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ECIESVectorTest.java 2016-08-27 01:21:44.000000000 +0000 @@ -117,13 +117,14 @@ doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "ECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding2, 128), p256_1_with_params22); doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "ECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding3, 128), p256_1_with_params23); - doTestNoParams("ECIES with P-256 None", keyPair, "OldECIES", p256_1_eph, old_p256_1_no_params); - doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding1, 128), old_p256_1_with_params11); - doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding2, 128), old_p256_1_with_params12); - doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding3, 128), old_p256_1_with_params13); - doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding1, 128), old_p256_1_with_params21); - doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding2, 128), old_p256_1_with_params22); - doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding3, 128), old_p256_1_with_params23); + // no longer supported +// doTestNoParams("ECIES with P-256 None", keyPair, "OldECIES", p256_1_eph, old_p256_1_no_params); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding1, 128), old_p256_1_with_params11); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding2, 128), old_p256_1_with_params12); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding3, 128), old_p256_1_with_params13); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding1, 128), old_p256_1_with_params21); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding2, 128), old_p256_1_with_params22); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding3, 128), old_p256_1_with_params23); keyPair = new KeyPair(ecFact.generatePublic(new X509EncodedKeySpec(p256_2_pub)), ecFact.generatePrivate(new PKCS8EncodedKeySpec(p256_2_pri))); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ECNRTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ECNRTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ECNRTest.java 2015-04-26 02:19:53.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ECNRTest.java 2016-09-28 01:10:59.000000000 +0000 @@ -23,6 +23,7 @@ import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomBigInteger; public class ECNRTest extends SimpleTest @@ -30,8 +31,9 @@ byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); - SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2 }); - + SecureRandom random = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2) }); + /** * X9.62 - 1998,
      * J.3.2, Page 155, ECDSA over the field Fp
      @@ -45,7 +47,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); ECCurve curve = new ECCurve.Fp( new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q @@ -89,7 +91,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("dcc5d1f1020906df2782360d36b2de7a17ece37d503784af", 16)); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); ECCurve.Fp curve = new ECCurve.Fp( new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q (or p) @@ -133,7 +135,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("cdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", 16)); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); ECCurve.Fp curve = new ECCurve.Fp( new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p) diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ElGamalTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ElGamalTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ElGamalTest.java 2012-03-14 00:09:28.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ElGamalTest.java 2016-08-23 01:55:33.000000000 +0000 @@ -14,6 +14,7 @@ import java.security.Security; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; +import java.util.HashSet; import javax.crypto.Cipher; import javax.crypto.interfaces.DHPrivateKey; @@ -471,6 +472,36 @@ } } + public void testGetExceptionsPKCS1() + throws Exception + { + SecureRandom rand = new SecureRandom(); + KeyPairGenerator keygen = KeyPairGenerator.getInstance("ELGAMAL", "BC"); + keygen.initialize(new DHParameterSpec(p1024, g1024), rand); + KeyPair keypair = keygen.genKeyPair(); + + Cipher c = Cipher.getInstance("ELGAMAL/ECB/PKCS1Padding", "BC"); + byte[] ciphertext = new byte[1024 / 8]; + HashSet exceptions = new HashSet(); + final int SAMPLES = 1000; + for (int i = 0; i < SAMPLES; i++) + { + rand.nextBytes(ciphertext); + ciphertext[0] = (byte)0; + try + { + c.init(Cipher.DECRYPT_MODE, keypair.getPrivate()); + c.doFinal(ciphertext); + } + catch (Exception ex) + { + String message = ex.toString(); + exceptions.add(message); + } + } + isTrue("exception count wrong", 1 == exceptions.size()); + } + public void performTest() throws Exception { @@ -485,6 +516,7 @@ testGP(1024, 256, g1024, p1024); testRandom(256); + testGetExceptionsPKCS1(); } public static void main( diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java 2015-08-13 07:00:27.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java 2016-09-29 23:44:55.000000000 +0000 @@ -44,8 +44,8 @@ import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.util.BigIntegers; import org.bouncycastle.util.Strings; -import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomBigInteger; import org.bouncycastle.x509.X509V3CertificateGenerator; public class GOST3410Test @@ -60,7 +60,7 @@ byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("53854137677348463731403841147996619241504003434302020712960838528893196233395")); - SecureRandom k = new FixedSecureRandom(kData); + SecureRandom k = new TestRandomBigInteger(kData); BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java 2016-07-26 06:09:48.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java 2016-10-05 23:57:04.000000000 +0000 @@ -3,10 +3,13 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Security; +import java.util.Arrays; import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.RC5ParameterSpec; import javax.crypto.spec.SecretKeySpec; @@ -24,50 +27,50 @@ public class HMacTest extends SimpleTest { - static byte[] keyBytes = Hex.decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); - static byte[] message = Hex.decode("4869205468657265"); - static byte[] output1 = Hex.decode("b617318655057264e28bc0b6fb378c8ef146be00"); - static byte[] outputMD5 = Hex.decode("5ccec34ea9656392457fa1ac27f08fbc"); - static byte[] outputMD2 = Hex.decode("dc1923ef5f161d35bef839ca8c807808"); - static byte[] outputMD4 = Hex.decode("5570ce964ba8c11756cdc3970278ff5a"); - static byte[] output224 = Hex.decode("896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"); - static byte[] output256 = Hex.decode("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"); - static byte[] output384 = Hex.decode("afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6"); - static byte[] output512 = Hex.decode("87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"); - static byte[] output512_224 = Hex.decode("b244ba01307c0e7a8ccaad13b1067a4cf6b961fe0c6a20bda3d92039"); - static byte[] output512_256 = Hex.decode("9f9126c3d9c3c330d760425ca8a217e31feae31bfe70196ff81642b868402eab"); - static byte[] outputRipeMD128 = Hex.decode("fda5717fb7e20cf05d30bb286a44b05d"); - static byte[] outputRipeMD160 = Hex.decode("24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668"); - static byte[] outputTiger = Hex.decode("1d7a658c75f8f004916e7b07e2a2e10aec7de2ae124d3647"); - static byte[] outputOld384 = Hex.decode("0a046aaa0255e432912228f8ccda437c8a8363fb160afb0570ab5b1fd5ddc20eb1888b9ed4e5b6cb5bc034cd9ef70e40"); - static byte[] outputOld512 = Hex.decode("9656975ee5de55e75f2976ecce9a04501060b9dc22a6eda2eaef638966280182477fe09f080b2bf564649cad42af8607a2bd8d02979df3a980f15e2326a0a22a"); - - static byte[] outputKck224 = Hex.decode("b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc"); - static byte[] outputKck256 = Hex.decode("9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821"); - static byte[] outputKck288 = Hex.decode("36145df8742160a1811139494d708f9a12757c30dedc622a98aa6ecb69da32a34ea55441"); - static byte[] outputKck384 = Hex.decode("892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048"); - static byte[] outputKck512 = Hex.decode("8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755"); - - static byte[] outputSha3_224 = Hex.decode("3b16546bbc7be2706a031dcafd56373d9884367641d8c59af3c860f7"); - static byte[] outputSha3_256 = Hex.decode("ba85192310dffa96e2a3a40e69774351140bb7185e1202cdcc917589f95e16bb"); - static byte[] outputSha3_384 = Hex.decode("68d2dcf7fd4ddd0a2240c8a437305f61fb7334cfb5d0226e1bc27dc10a2e723a20d370b47743130e26ac7e3d532886bd"); - static byte[] outputSha3_512 = Hex.decode("eb3fbd4b2eaab8f5c504bd3a41465aacec15770a7cabac531e482f860b5ec7ba47ccb2c6f2afce8f88d22b6dc61380f23a668fd3888bb80537c0a0b86407689e"); + static byte[] keyBytes = Hex.decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); + static byte[] message = Hex.decode("4869205468657265"); + static byte[] output1 = Hex.decode("b617318655057264e28bc0b6fb378c8ef146be00"); + static byte[] outputMD5 = Hex.decode("5ccec34ea9656392457fa1ac27f08fbc"); + static byte[] outputMD2 = Hex.decode("dc1923ef5f161d35bef839ca8c807808"); + static byte[] outputMD4 = Hex.decode("5570ce964ba8c11756cdc3970278ff5a"); + static byte[] output224 = Hex.decode("896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"); + static byte[] output256 = Hex.decode("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"); + static byte[] output384 = Hex.decode("afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6"); + static byte[] output512 = Hex.decode("87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"); + static byte[] output512_224 = Hex.decode("b244ba01307c0e7a8ccaad13b1067a4cf6b961fe0c6a20bda3d92039"); + static byte[] output512_256 = Hex.decode("9f9126c3d9c3c330d760425ca8a217e31feae31bfe70196ff81642b868402eab"); + static byte[] outputRipeMD128 = Hex.decode("fda5717fb7e20cf05d30bb286a44b05d"); + static byte[] outputRipeMD160 = Hex.decode("24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668"); + static byte[] outputTiger = Hex.decode("1d7a658c75f8f004916e7b07e2a2e10aec7de2ae124d3647"); + static byte[] outputOld384 = Hex.decode("0a046aaa0255e432912228f8ccda437c8a8363fb160afb0570ab5b1fd5ddc20eb1888b9ed4e5b6cb5bc034cd9ef70e40"); + static byte[] outputOld512 = Hex.decode("9656975ee5de55e75f2976ecce9a04501060b9dc22a6eda2eaef638966280182477fe09f080b2bf564649cad42af8607a2bd8d02979df3a980f15e2326a0a22a"); + + static byte[] outputKck224 = Hex.decode("b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc"); + static byte[] outputKck256 = Hex.decode("9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821"); + static byte[] outputKck288 = Hex.decode("36145df8742160a1811139494d708f9a12757c30dedc622a98aa6ecb69da32a34ea55441"); + static byte[] outputKck384 = Hex.decode("892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048"); + static byte[] outputKck512 = Hex.decode("8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755"); + + static byte[] outputSha3_224 = Hex.decode("3b16546bbc7be2706a031dcafd56373d9884367641d8c59af3c860f7"); + static byte[] outputSha3_256 = Hex.decode("ba85192310dffa96e2a3a40e69774351140bb7185e1202cdcc917589f95e16bb"); + static byte[] outputSha3_384 = Hex.decode("68d2dcf7fd4ddd0a2240c8a437305f61fb7334cfb5d0226e1bc27dc10a2e723a20d370b47743130e26ac7e3d532886bd"); + static byte[] outputSha3_512 = Hex.decode("eb3fbd4b2eaab8f5c504bd3a41465aacec15770a7cabac531e482f860b5ec7ba47ccb2c6f2afce8f88d22b6dc61380f23a668fd3888bb80537c0a0b86407689e"); - static byte[] outputGost2012_256 = Hex.decode("f03422dfa37a507ca126ce01b8eba6b7fdda8f8a60dd8f2703e3a372120b8294"); - static byte[] outputGost2012_512 = Hex.decode("86b6a06bfa9f1974aff6ccd7fa3f835f0bd850395d6084efc47b9dda861a2cdf0dcaf959160733d5269f6567966dd7a9f932a77cd6f080012cd476f1c2cc31bb"); + static byte[] outputGost2012_256 = Hex.decode("f03422dfa37a507ca126ce01b8eba6b7fdda8f8a60dd8f2703e3a372120b8294"); + static byte[] outputGost2012_512 = Hex.decode("86b6a06bfa9f1974aff6ccd7fa3f835f0bd850395d6084efc47b9dda861a2cdf0dcaf959160733d5269f6567966dd7a9f932a77cd6f080012cd476f1c2cc31bb"); public HMacTest() { } public void testHMac( - String hmacName, - byte[] output) + String hmacName, + byte[] output) throws Exception { - SecretKey key = new SecretKeySpec(keyBytes, hmacName); - byte[] out; - Mac mac; + SecretKey key = new SecretKeySpec(keyBytes, hmacName); + byte[] out; + Mac mac; mac = Mac.getInstance(hmacName, "BC"); @@ -100,14 +103,14 @@ } public void testHMac( - String hmacName, - int defKeySize, - byte[] output) + String hmacName, + int defKeySize, + byte[] output) throws Exception { - SecretKey key = new SecretKeySpec(keyBytes, hmacName); - byte[] out; - Mac mac; + SecretKey key = new SecretKeySpec(keyBytes, hmacName); + byte[] out; + Mac mac; mac = Mac.getInstance(hmacName, "BC"); @@ -145,7 +148,7 @@ mac = Mac.getInstance("HmacSHA1", "BC"); - byte [] b = {(byte)1, (byte)2, (byte)3, (byte)4, (byte)5}; + byte[] b = {(byte)1, (byte)2, (byte)3, (byte)4, (byte)5}; SecretKeySpec sks = new SecretKeySpec(b, "HmacSHA1"); RC5ParameterSpec algPS = new RC5ParameterSpec(100, 100, 100); @@ -256,6 +259,55 @@ testHMac("OldHMacSHA512", outputOld512); testExceptions(); + + testPBEWITHHMACSHAVariants(); + } + + private static final int[] SUN_JCA_VARIANTS = { + 1, 224, 256, 384, 512 + }; + + private static final byte[][] SUN_JCA_KNOWN_ANSWERS_FOR_SHA_VARIANTS = { + Hex.decode("2cb29f938331443af79de5863a1b072d57a4b640"), + Hex.decode("3bf31c354fb1817503e9b581d4d1d51c4c8e921a3b46a513cc24c0ca"), + Hex.decode("583697860e49d8d534ebdf99205173356f4e209447b6ac7d500ddddc1b382068"), + Hex.decode("ad3ca42cc656876872bd0e5054d0f2260ec2a07635c5dfa655926989af392bbe636a23f08d1dc8ccd966ffa66ecc30e0"), + Hex.decode("eabbb30bf280870530126bea40d3123c18d6bd6f6e9ded0eebd51a44d8527b27732206bd1bb7c1c8d941b5f2fba2f87ed49f5f1f3d7bef0e7547d335b4a55b87") + }; + + /** + * Test that BC has the same results as the SunJCA provider for PBEwithHMACSHA. + *

      + * Test courtesy of the Android project. + *

      + */ + public void testPBEWITHHMACSHAVariants() + throws Exception + { + byte[] plaintext = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}; + byte[] salt = "saltsalt".getBytes(); + char[] password = "password".toCharArray(); + int iterationCount = 100; + + for (int shaVariantIndex = 0; shaVariantIndex < SUN_JCA_VARIANTS.length; shaVariantIndex++) + { + int shaVariant = SUN_JCA_VARIANTS[shaVariantIndex]; + SecretKeyFactory secretKeyFactory = + SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA" + shaVariant, "BC"); + PBEKeySpec pbeKeySpec = new PBEKeySpec(password, + salt, + iterationCount, + // Key depending on block size! + (shaVariant < 384) ? 64 : 128); + SecretKey secretKey = secretKeyFactory.generateSecret(pbeKeySpec); + Mac mac = Mac.getInstance("PBEWITHHMACSHA" + shaVariant, "BC"); + mac.init(secretKey); + + byte[] bcResult = mac.doFinal(plaintext); + + isTrue("value mismatch", Arrays.equals(SUN_JCA_KNOWN_ANSWERS_FOR_SHA_VARIANTS[shaVariantIndex], bcResult)); + } } public String getName() @@ -264,7 +316,7 @@ } public static void main( - String[] args) + String[] args) { Security.addProvider(new BouncyCastleProvider()); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java 2013-09-29 09:08:28.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java 2016-09-28 01:12:31.000000000 +0000 @@ -36,7 +36,8 @@ byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); - SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2 }); + SecureRandom random = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2) }); public void performTest() throws Exception diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/NamedCurveTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/NamedCurveTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/NamedCurveTest.java 2016-06-23 04:49:42.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/NamedCurveTest.java 2016-10-18 03:37:56.000000000 +0000 @@ -1,15 +1,5 @@ package org.bouncycastle.jce.provider.test; -import org.bouncycastle.asn1.nist.NISTNamedCurves; -import org.bouncycastle.asn1.sec.SECNamedCurves; -import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; -import org.bouncycastle.asn1.x9.X962NamedCurves; -import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.jce.spec.ECNamedCurveSpec; -import org.bouncycastle.util.test.SimpleTest; - -import javax.crypto.KeyAgreement; import java.math.BigInteger; import java.security.KeyFactory; import java.security.KeyPair; @@ -22,12 +12,28 @@ import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.ECGenParameterSpec; +import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; +import java.util.Collections; import java.util.Enumeration; +import java.util.HashSet; import java.util.Hashtable; import java.util.Set; -import java.util.HashSet; + +import javax.crypto.KeyAgreement; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; +import org.bouncycastle.asn1.nist.NISTNamedCurves; +import org.bouncycastle.asn1.sec.SECNamedCurves; +import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x9.X962NamedCurves; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECNamedCurveSpec; +import org.bouncycastle.util.test.SimpleTest; public class NamedCurveTest extends SimpleTest @@ -282,6 +288,79 @@ } } + public void testAcceptable() + throws Exception + { + ECGenParameterSpec ecSpec = new ECGenParameterSpec("P-256"); + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC"); + + kpGen.initialize(ecSpec); + + KeyPair kp = kpGen.generateKeyPair(); + + X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(kp.getPublic().getEncoded()); + PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded()); + + KeyFactory kf = KeyFactory.getInstance("EC", "BC"); + + ConfigurableProvider bcProv = ((ConfigurableProvider)Security.getProvider("BC")); + + bcProv.setParameter(ConfigurableProvider.ACCEPTABLE_EC_CURVES, Collections.singleton(NISTNamedCurves.getOID("P-384"))); + + try + { + kf.generatePrivate(privSpec); + fail("no exception"); + } + catch (InvalidKeySpecException e) + { + isTrue("wrong message", "encoded key spec not recognized: named curve not acceptable".equals(e.getMessage())); + } + + try + { + kf.generatePublic(pubSpec); + fail("no exception"); + } + catch (InvalidKeySpecException e) + { + isTrue("wrong message", "encoded key spec not recognized: named curve not acceptable".equals(e.getMessage())); + } + + bcProv.setParameter(ConfigurableProvider.ACCEPTABLE_EC_CURVES, Collections.singleton(NISTNamedCurves.getOID("P-256"))); + + kf.generatePrivate(privSpec); + kf.generatePublic(pubSpec); + + bcProv.setParameter(ConfigurableProvider.ACCEPTABLE_EC_CURVES, Collections.EMPTY_SET); + + kf.generatePrivate(privSpec); + kf.generatePublic(pubSpec); + } + + public void testAdditional() + throws Exception + { + ConfigurableProvider bcProv = ((ConfigurableProvider)Security.getProvider("BC")); + ASN1ObjectIdentifier bogusCurveID = Extension.auditIdentity; + + bcProv.setParameter(ConfigurableProvider.ADDITIONAL_EC_PARAMETERS, Collections.singletonMap(bogusCurveID, NISTNamedCurves.getByName("P-384"))); + + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC"); + + kpGen.initialize(new ECGenParameterSpec(bogusCurveID.getId())); + + KeyPair kp = kpGen.generateKeyPair(); + + X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(kp.getPublic().getEncoded()); + PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded()); + + KeyFactory kf = KeyFactory.getInstance("EC", "BC"); + + kf.generatePrivate(privSpec); + kf.generatePublic(pubSpec); + } + public String getName() { return "NamedCurve"; @@ -329,6 +408,9 @@ { testECGOST((String)en.nextElement()); } + + testAcceptable(); + testAdditional(); } public static void main( diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/Poly1305Test.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/Poly1305Test.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/Poly1305Test.java 2016-01-18 20:43:52.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/Poly1305Test.java 2016-08-31 01:09:26.000000000 +0000 @@ -33,6 +33,7 @@ public void performTest() throws Exception { + checkRawPoly1305(); checkRegistrations(); } @@ -98,6 +99,38 @@ } } + private void checkRawPoly1305() + throws Exception + { + checkMac("Poly1305", "e8bd1466eaf442dd71598370c1e34392"); + } + + private void checkMac(String name, String macOutput) + throws Exception + { + KeyGenerator kg = KeyGenerator.getInstance(name); + SecretKey key = kg.generateKey(); + + try + { + Poly1305KeyGenerator.checkKey(key.getEncoded()); + } + catch (IllegalArgumentException e) + { + fail("Generated key for algo " + name + " does not match required Poly1305 format."); + } + + Mac mac = Mac.getInstance(name); + mac.init(new SecretKeySpec(MASTER_KEY, name)); + mac.update(new byte[128]); + byte[] bytes = mac.doFinal(); + + if (!Arrays.areEqual(bytes, Hex.decode(macOutput))) + { + fail("wrong mac value computed for " + name, macOutput, new String(Hex.encode(bytes))); + } + } + private void checkMac(String name, List missingMacs, List missingKeyGens, String macOutput) { try diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java 2016-03-05 20:37:44.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java 2016-09-29 23:44:54.000000000 +0000 @@ -20,8 +20,8 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.test.FixedSecureRandom; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestRandomData; public class PSSTest extends SimpleTest @@ -236,7 +236,7 @@ byte[] fixedRandomBytes = new byte[saltLen]; random.nextBytes(fixedRandomBytes); - normalSig.initSign(privKey, new FixedSecureRandom(fixedRandomBytes)); + normalSig.initSign(privKey, new TestRandomData(fixedRandomBytes)); normalSig.update(sampleMessage); byte[] normalResult = normalSig.sign(); @@ -248,7 +248,7 @@ // Need to init the params explicitly to avoid having a 'raw' variety of every PSS algorithm rawSig.setParameter(spec); - rawSig.initSign(privKey, new FixedSecureRandom(fixedRandomBytes)); + rawSig.initSign(privKey, new TestRandomData(fixedRandomBytes)); rawSig.update(hash); byte[] rawResult = rawSig.sign(); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java 2016-06-28 04:54:12.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java 2016-12-08 03:44:43.000000000 +0000 @@ -79,7 +79,8 @@ new DetDSATest(), new ThreefishTest(), new SM4Test(), - new TLSKDFTest() + new TLSKDFTest(), + new BCFKSStoreTest() }; public static void main( diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java 2016-03-05 20:27:30.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java 2016-11-19 06:08:00.000000000 +0000 @@ -26,6 +26,7 @@ import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import java.security.spec.X509EncodedKeySpec; +import java.util.HashSet; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; @@ -705,6 +706,7 @@ out = c.update(new byte[40]); + testGetExceptionsPKCS1(); zeroMessageTest(); oaepDigestCheck("SHA3-224", NISTObjectIdentifiers.id_sha3_224, pub2048Key, priv2048Key, rand, Hex.decode("2aa7812d4f7b7766f8625feb58481ef5b5fa6dfafbea543e4bbba89d6708f4900fc9fd55d5c2b83fefefc67e2ba7a4222217efaa9b9d31920bdcd78733319aca910dfd118aae5e901a6d27a56e37b1a6f86e7404f82da248e77845e58b789f10a1af8a1208f77dda384692609339346c4ea57928b890042e7d70b1d5817f8978dcbc9cd2fcdde37a0a41a52dbef701ddc859a5d58efd10aa5bd8d205c10154db906540bf20dedcff721df11a456df201cb9cbbd092a89a1eb3f11e7e34003d7070e02c8db54e5498e7ee262fb9178f5eb85d1db66baafe0a66e8283df9c41bded218e5d906d28f08803deb3cbd1a92777d55fe56ff022a47f673cac2ca145973")); @@ -758,6 +760,35 @@ } + public void testGetExceptionsPKCS1() + throws Exception + { + KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA", "BC"); + keygen.initialize(1024); + KeyPair keypair = keygen.genKeyPair(); + SecureRandom rand = new SecureRandom(); + Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC"); + byte[] ciphertext = new byte[1024 / 8]; + HashSet exceptions = new HashSet(); + final int SAMPLES = 1000; + for (int i = 0; i < SAMPLES; i++) + { + rand.nextBytes(ciphertext); + ciphertext[0] = (byte)0; + try + { + c.init(Cipher.DECRYPT_MODE, keypair.getPrivate()); + c.doFinal(ciphertext); + } + catch (Exception ex) + { + String message = ex.toString(); + exceptions.add(message); + } + } + isTrue("exception count wrong", 1 == exceptions.size()); + } + public void zeroMessageTest() throws Exception { diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/SigTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/SigTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/SigTest.java 2016-04-25 05:05:27.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/SigTest.java 2016-09-12 00:16:22.000000000 +0000 @@ -237,14 +237,14 @@ tryRsaPkcs15Sig("SHA256WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256); tryRsaPkcs15Sig("SHA384WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384); tryRsaPkcs15Sig("SHA512WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512); - trySig("SHA512(224)WithRSA", data, signingKey, verifyKey); - trySig("SHA512(256)WithRSA", data, signingKey, verifyKey); + tryRsaPkcs15Sig("SHA512(224)WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_224WithRSAEncryption, NISTObjectIdentifiers.id_sha512_224); + tryRsaPkcs15Sig("SHA512(256)WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_256WithRSAEncryption, NISTObjectIdentifiers.id_sha512_256); tryRsaPkcs15Sig("SHA224WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224); tryRsaPkcs15Sig("SHA256WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256); tryRsaPkcs15Sig("SHA384WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384); tryRsaPkcs15Sig("SHA512WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512); - trySig("SHA512(224)WithRSAEncryption", data, signingKey, verifyKey); - trySig("SHA512(256)WithRSAEncryption", data, signingKey, verifyKey); + tryRsaPkcs15Sig("SHA512(224)WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_224WithRSAEncryption, NISTObjectIdentifiers.id_sha512_224); + tryRsaPkcs15Sig("SHA512(256)WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_256WithRSAEncryption, NISTObjectIdentifiers.id_sha512_256); tryRsaPkcs15Sig("SHA3-224WithRSA", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_224, NISTObjectIdentifiers.id_sha3_224); tryRsaPkcs15Sig("SHA3-256WithRSA", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_256, NISTObjectIdentifiers.id_sha3_256); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/TestUtils.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/TestUtils.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/jce/provider/test/TestUtils.java 2015-10-04 22:37:16.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/jce/provider/test/TestUtils.java 2016-12-19 01:18:41.000000000 +0000 @@ -53,6 +53,7 @@ import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator; import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; import org.bouncycastle.asn1.x509.X509Extensions; +import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.jce.PrincipalUtil; @@ -72,6 +73,8 @@ algIds.put("GOST3411withGOST3410", new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94)); algIds.put("SHA1withRSA", new AlgorithmIdentifier(PKCSObjectIdentifiers.sha1WithRSAEncryption, DERNull.INSTANCE)); algIds.put("SHA256withRSA", new AlgorithmIdentifier(PKCSObjectIdentifiers.sha256WithRSAEncryption, DERNull.INSTANCE)); + algIds.put("SHA1withECDSA", new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA1)); + algIds.put("SHA256withECDSA", new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256)); } public static X509Certificate createSelfSignedCert(String dn, String sigName, KeyPair keyPair) @@ -257,6 +260,18 @@ return new ExceptionCertificate(exceptionOnEncode); } + public static X500Name getCertIssuer(X509Certificate x509Certificate) + throws CertificateEncodingException + { + return TBSCertificate.getInstance(x509Certificate.getTBSCertificate()).getIssuer(); + } + + public static X500Name getCertSubject(X509Certificate x509Certificate) + throws CertificateEncodingException + { + return TBSCertificate.getInstance(x509Certificate.getTBSCertificate()).getSubject(); + } + private static class ExceptionCertificate extends X509Certificate { diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java 2016-03-31 02:11:47.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java 2016-08-29 02:04:47.000000000 +0000 @@ -33,6 +33,10 @@ suite.addTestSuite(McElieceCipherTest.class); suite.addTestSuite(McElieceKeyPairGeneratorTest.class); suite.addTestSuite(McElieceCCA2KeyPairGeneratorTest.class); + suite.addTestSuite(NewHopeTest.class); + suite.addTestSuite(NewHopeKeyPairGeneratorTest.class); + suite.addTestSuite(Sphincs256Test.class); + suite.addTestSuite(Sphincs256KeyPairGeneratorTest.class); return new BCTestSetup(suite); } diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeKeyPairGeneratorTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeKeyPairGeneratorTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeKeyPairGeneratorTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeKeyPairGeneratorTest.java 2016-08-29 02:16:26.000000000 +0000 @@ -0,0 +1,37 @@ +package org.bouncycastle.pqc.jcajce.provider.test; + +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; + +import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; + + +public class NewHopeKeyPairGeneratorTest + extends KeyPairGeneratorTest +{ + + protected void setUp() + { + super.setUp(); + } + + public void testKeyFactory() + throws Exception + { + kf = KeyFactory.getInstance("NH", "BCPQC"); + kf = KeyFactory.getInstance(PQCObjectIdentifiers.newHope.getId(), "BCPQC"); + } + + public void testKeyPairEncoding() + throws Exception + { + kf = KeyFactory.getInstance("NH", "BCPQC"); + + kpg = KeyPairGenerator.getInstance("NH", "BCPQC"); + kpg.initialize(1024, new SecureRandom()); + + performKeyPairEncodingTest(kpg.generateKeyPair()); + } + +} diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeTest.java 2016-02-24 11:49:32.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeTest.java 2016-09-29 23:44:16.000000000 +0000 @@ -34,7 +34,7 @@ { KeyPairGenerator kpGen = KeyPairGenerator.getInstance("NH", "BCPQC"); - kpGen.initialize(2048, aliceRand); + kpGen.initialize(1024, aliceRand); KeyPair aliceKp = kpGen.generateKeyPair(); diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowSignatureTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowSignatureTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowSignatureTest.java 2013-05-31 06:20:21.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowSignatureTest.java 2016-08-29 02:04:47.000000000 +0000 @@ -92,7 +92,7 @@ { // generate new signature instance for verification // sigVerify = (Signature) sig.getClass().newInstance(); - sigVerify = Signature.getInstance("SHA384WITHRainbow"); + sigVerify = Signature.getInstance("SHA384withRainbow", "BCPQC"); for (int j = 0; j < numPassesKPG; j++) { diff -Nru bouncycastle-1.55/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256KeyPairGeneratorTest.java bouncycastle-1.56/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256KeyPairGeneratorTest.java --- bouncycastle-1.55/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256KeyPairGeneratorTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256KeyPairGeneratorTest.java 2016-08-29 02:16:26.000000000 +0000 @@ -0,0 +1,37 @@ +package org.bouncycastle.pqc.jcajce.provider.test; + +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; + +import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; +import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec; + + +public class Sphincs256KeyPairGeneratorTest + extends KeyPairGeneratorTest +{ + + protected void setUp() + { + super.setUp(); + } + + public void testKeyFactory() + throws Exception + { + kf = KeyFactory.getInstance("SPHINCS256", "BCPQC"); + kf = KeyFactory.getInstance(PQCObjectIdentifiers.newHope.getId(), "BCPQC"); + } + + public void testKeyPairEncoding() + throws Exception + { + kf = KeyFactory.getInstance("SPHINCS256", "BCPQC"); + + kpg = KeyPairGenerator.getInstance("SPHINCS256", "BCPQC"); + kpg.initialize(new SPHINCS256KeyGenParameterSpec(SPHINCS256KeyGenParameterSpec.SHA512_256), new SecureRandom()); + performKeyPairEncodingTest(kpg.generateKeyPair()); + } + +} diff -Nru bouncycastle-1.55/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java bouncycastle-1.56/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java --- bouncycastle-1.55/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java 2016-12-20 01:53:07.000000000 +0000 @@ -0,0 +1,732 @@ +package org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.util.Date; +import java.util.Enumeration; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.test.SimpleTest; + +/** + * Exercise the BCFKS KeyStore, + */ +public class BCFKSStoreTest + extends SimpleTest +{ + private static byte[] trustedCertData = Base64.decode( + "MIIB/DCCAaagAwIBAgIBATANBgkqhkiG9w0BAQQFADCBhjELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb24gb2YgdGhlIE" + + "JvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExJjAkBgkqhkiG9w0BCQEWF2lzc3VlckBi" + + "b3VuY3ljYXN0bGUub3JnMB4XDTE0MDIyODExMjcxMVoXDTE0MDQyOTExMjcxMVowgYcxCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaG" + + "UgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMScwJQYJKoZI" + + "hvcNAQkBFhhzdWJqZWN0QGJvdW5jeWNhc3RsZS5vcmcwWjANBgkqhkiG9w0BAQEFAANJADBGAkEAtKfkYXBXTxapcIKyK+WLaipil5" + + "hBm+EocqS9umJs+umQD3ar+xITnc5d5WVk+rK2VDFloEDGBoh0IOM9ke1+1wIBETANBgkqhkiG9w0BAQQFAANBAJ/ZhfF21NykhbEY" + + "RQrAo/yRr9XfpmBTVUSlLJXYoNVVRT5u9SGQqmPNfHElrTvNMZQPC0ridDZtBWb6S2tg9/E="); + + static char[] testPassword = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}; + static char[] invalidTestPassword = {'Y', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}; + + + public void shouldCreateEmptyBCFKSNoPassword() + throws Exception + { + checkEmptyStore(null); + } + + public void shouldCreateEmptyBCFKSPassword() + throws Exception + { + checkEmptyStore(testPassword); + } + + private void checkEmptyStore(char[] passwd) + throws KeyStoreException, NoSuchProviderException, IOException, NoSuchAlgorithmException, CertificateException + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + } + + private void checkInvalidLoad(KeyStore store, char[] passwd, byte[] data) + throws NoSuchAlgorithmException, CertificateException, KeyStoreException + { + checkInvalidLoadForPassword(store, invalidTestPassword, data); + + if (passwd != null) + { + checkInvalidLoadForPassword(store, null, data); + } + } + + private void checkInvalidLoadForPassword(KeyStore store, char[] password, byte[] data) + throws NoSuchAlgorithmException, CertificateException, KeyStoreException + { + try + { + store.load(new ByteArrayInputStream(data), password); + } + catch (IOException e) + { + isTrue("wrong message", "BCFKS KeyStore corrupted: MAC calculation failed.".equals(e.getMessage())); + } + + isTrue("", 0 == store.size()); + isTrue("", !store.aliases().hasMoreElements()); + } + + public void shouldStoreOneCertificate() + throws Exception + { + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + checkOneCertificate(cert, null); + checkOneCertificate(cert, testPassword); + } + + private void checkOneCertificate(X509Certificate cert, char[] passwd) + throws KeyStoreException, NoSuchProviderException, IOException, NoSuchAlgorithmException, CertificateException + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setCertificateEntry("cert", cert); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "cert".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + certStorageCheck(store1, "cert", cert); + + Date entryDate = store1.getCreationDate("cert"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", entryDate.equals(store2.getCreationDate("cert"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "cert".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + certStorageCheck(store2, "cert", cert); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("cert"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + public void shouldStoreOnePrivateKey() + throws Exception + { + PrivateKey privKey = getPrivateKey(); + + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + checkOnePrivateKeyFips(privKey, new X509Certificate[] { cert }, null); + checkOnePrivateKeyFips(privKey, new X509Certificate[] { cert }, testPassword); + checkOnePrivateKeyDef(privKey, new X509Certificate[] { cert }, null); + checkOnePrivateKeyDef(privKey, new X509Certificate[] { cert }, testPassword); + } + + public void shouldStoreOnePrivateKeyWithChain() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(512); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withRSA", + null, + kp1.getPublic()); + + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + } + + public void shouldStoreOneECKeyWithChain() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC"); + + kpGen.initialize(256); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withECDSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withECDSA", + null, + kp1.getPublic()); + + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + } + + public void shouldRejectInconsistentKeys() + throws Exception + { + PrivateKey privKey = getPrivateKey(); + + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.interCertBin)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + try + { + store1.setKeyEntry("privkey", privKey, "hello".toCharArray(), new X509Certificate[]{interCert}); + fail("no exception"); + } + catch (KeyStoreException e) + { + // isTrue("", "RSA keys do not have the same modulus".equals(e.getCause().getMessage())); + } + } + + private void checkOnePrivateKeyFips(PrivateKey key, X509Certificate[] certs, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + checkOnePrivateKey(key, store1, certs, passwd); + } + + private void checkOnePrivateKeyDef(PrivateKey key, X509Certificate[] certs, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS-DEF", "BC"); + + store1.load(null, null); + + checkOnePrivateKey(key, store1, certs, passwd); + } + + private void checkOnePrivateKey(PrivateKey key, KeyStore store1, X509Certificate[] certs, char[] passwd) + throws Exception + { + store1.setKeyEntry("privkey", key, passwd, certs); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "privkey".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + privateKeyStorageCheck(store1, "privkey", key, certs[0], passwd); + + Date entryDate = store1.getCreationDate("privkey"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", store2.getCertificateChain("privkey").length == certs.length); + Certificate[] sChain = store2.getCertificateChain("privkey"); + for (int i = 0; i != sChain.length; i++) + { + isTrue("", certs[i].equals(sChain[i])); + } + isTrue("", entryDate.equals(store2.getCreationDate("privkey"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "privkey".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + privateKeyStorageCheck(store2, "privkey", key, certs[0], passwd); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("privkey"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + public void shouldStoreMultipleKeys() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(512); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withRSA", + null, + kp1.getPublic()); + + PrivateKey privKey = kp1.getPrivate(); + + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(trustedCertData)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setKeyEntry("privkey", privKey, testPassword, new X509Certificate[]{interCert, finalCert}); + store1.setCertificateEntry("trusted", cert); + SecretKeySpec aesKey = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "AES"); + store1.setKeyEntry("secret1", aesKey, "secretPwd1".toCharArray(), null); + SecretKeySpec edeKey = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "DESede"); + store1.setKeyEntry("secret2", edeKey, "secretPwd2".toCharArray(), null); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, testPassword); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), testPassword); + + isTrue("", 4 ==store2.size()); + + Key storeDesEde = store2.getKey("secret2", "secretPwd2".toCharArray()); + + isTrue("", edeKey.getAlgorithm().equals(storeDesEde.getAlgorithm())); + + isTrue("", Arrays.areEqual(edeKey.getEncoded(), storeDesEde.getEncoded())); + + Key storeAes = store2.getKey("secret1", "secretPwd1".toCharArray()); + isTrue("", Arrays.areEqual(aesKey.getEncoded(), storeAes.getEncoded())); + isTrue("", aesKey.getAlgorithm().equals(storeAes.getAlgorithm())); + + Key storePrivKey = store2.getKey("privkey", testPassword); + isTrue("", privKey.equals(storePrivKey)); + isTrue("", 2 == store2.getCertificateChain("privkey").length); + + Certificate storeCert = store2.getCertificate("trusted"); + isTrue("", cert.equals(storeCert)); + + isTrue("", null ==store2.getCertificate("unknown")); + + isTrue("", null ==store2.getCertificateChain("unknown")); + + isTrue("", !store2.isCertificateEntry("unknown")); + + isTrue("", !store2.isKeyEntry("unknown")); + + isTrue("", !store2.containsAlias("unknown")); + } + + public void shouldStoreSecretKeys() + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + SecretKeySpec aesKey = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "AES"); + SecretKeySpec edeKey1 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "DESede"); + SecretKeySpec edeKey2 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "TripleDES"); + SecretKeySpec edeKey3 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "TDEA"); + SecretKeySpec hmacKey1 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff"), "HmacSHA1"); + SecretKeySpec hmacKey224 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff"), "HmacSHA224"); + SecretKeySpec hmacKey256 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff01ff"), "HmacSHA256"); + SecretKeySpec hmacKey384 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff0102ff"), "HmacSHA384"); + SecretKeySpec hmacKey512 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff010203ff"), "HmacSHA512"); + + store1.setKeyEntry("secret1", aesKey, "secretPwd1".toCharArray(), null); + store1.setKeyEntry("secret2", edeKey1, "secretPwd2".toCharArray(), null); + store1.setKeyEntry("secret3", edeKey2, "secretPwd3".toCharArray(), null); + store1.setKeyEntry("secret4", edeKey3, "secretPwd4".toCharArray(), null); + store1.setKeyEntry("secret5", hmacKey1, "secretPwd5".toCharArray(), null); + store1.setKeyEntry("secret6", hmacKey224, "secretPwd6".toCharArray(), null); + store1.setKeyEntry("secret7", hmacKey256, "secretPwd7".toCharArray(), null); + store1.setKeyEntry("secret8", hmacKey384, "secretPwd8".toCharArray(), null); + store1.setKeyEntry("secret9", hmacKey512, "secretPwd9".toCharArray(), null); + + checkSecretKey(store1, "secret1", "secretPwd1".toCharArray(), aesKey); + checkSecretKey(store1, "secret2", "secretPwd2".toCharArray(), edeKey1); // TRIPLEDES and TDEA will convert to DESEDE + checkSecretKey(store1, "secret3", "secretPwd3".toCharArray(), edeKey1); + checkSecretKey(store1, "secret4", "secretPwd4".toCharArray(), edeKey1); + checkSecretKey(store1, "secret5", "secretPwd5".toCharArray(), hmacKey1); + checkSecretKey(store1, "secret6", "secretPwd6".toCharArray(), hmacKey224); + checkSecretKey(store1, "secret7", "secretPwd7".toCharArray(), hmacKey256); + checkSecretKey(store1, "secret8", "secretPwd8".toCharArray(), hmacKey384); + checkSecretKey(store1, "secret9", "secretPwd9".toCharArray(), hmacKey512); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, "secretkeytest".toCharArray()); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), "secretkeytest".toCharArray()); + + checkSecretKey(store2, "secret1", "secretPwd1".toCharArray(), aesKey); + checkSecretKey(store2, "secret2", "secretPwd2".toCharArray(), edeKey1); // TRIPLEDES and TDEA will convert to DESEDE + checkSecretKey(store2, "secret3", "secretPwd3".toCharArray(), edeKey1); + checkSecretKey(store2, "secret4", "secretPwd4".toCharArray(), edeKey1); + checkSecretKey(store2, "secret5", "secretPwd5".toCharArray(), hmacKey1); + checkSecretKey(store2, "secret6", "secretPwd6".toCharArray(), hmacKey224); + checkSecretKey(store2, "secret7", "secretPwd7".toCharArray(), hmacKey256); + checkSecretKey(store2, "secret8", "secretPwd8".toCharArray(), hmacKey384); + checkSecretKey(store2, "secret9", "secretPwd9".toCharArray(), hmacKey512); + + isTrue("", null ==store2.getKey("secret10", new char[0])); + } + + private void checkSecretKey(KeyStore store, String alias, char[] passwd, SecretKey key) + throws Exception + { + SecretKey sKey = (SecretKey)store.getKey(alias, passwd); + + isTrue("", Arrays.areEqual(key.getEncoded(), sKey.getEncoded())); + isTrue("", key.getAlgorithm().equals(sKey.getAlgorithm())); + + if (!store.isKeyEntry(alias)) + { + fail("key not identified as key entry"); + } + } + + private PrivateKey getPrivateKey() + { + PrivateKey privKey = null; + + RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16), + new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16), + new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16), + new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16), + new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16), + new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16), + new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16)); + + + try + { + KeyFactory fact = KeyFactory.getInstance("RSA", "BC"); + + privKey = fact.generatePrivate(privKeySpec); + } + catch (Exception e) + { + fail("error setting up keys - " + e.toString()); + } + + return privKey; + } + + public void shouldStoreOneSecretKey() + throws Exception + { + checkOneSecretKey(new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "AES"), null); + checkOneSecretKey(new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "AES"), testPassword); + } + + private void checkOneSecretKey(SecretKey key, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setKeyEntry("seckey", key, passwd, null); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "seckey".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + secretKeyStorageCheck(store1, "seckey", key, passwd); + + Date entryDate = store1.getCreationDate("seckey"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", entryDate.equals(store2.getCreationDate("seckey"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "seckey".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + secretKeyStorageCheck(store2, "seckey", key, passwd); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("seckey"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + private void privateKeyStorageCheck(KeyStore store, String keyName, PrivateKey key, Certificate cert, char[] password) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException + { + if (!store.containsAlias(keyName)) + { + fail("couldn't find alias privateKey"); + } + + if (store.isCertificateEntry(keyName)) + { + fail("key identified as certificate entry"); + } + + if (!store.isKeyEntry(keyName)) + { + fail("key not identified as key entry"); + } + + Key storeKey = store.getKey(keyName, password); + + if (store.getType().equals("BCFKS")) + { + isTrue("", key.equals(storeKey)); + } + + if (password != null) + { + try + { + store.getKey(keyName, null); + } + catch (UnrecoverableKeyException e) + { + isTrue("",e.getMessage().startsWith("BCFKS KeyStore unable to recover private key (privkey)")); + } + } + + Certificate[] certificateChain = store.getCertificateChain(keyName); + if (certificateChain == null) + { + fail("Did not return certificate chain"); + } + isTrue("", cert.equals(certificateChain[0])); + + isTrue("", keyName.equals(store.getCertificateAlias(cert))); + } + + private void certStorageCheck(KeyStore store, String certName, Certificate cert) + throws KeyStoreException + { + if (!store.containsAlias(certName)) + { + fail("couldn't find alias " + certName); + } + + if (!store.isCertificateEntry(certName)) + { + fail("cert not identified as certificate entry"); + } + + if (store.isKeyEntry(certName)) + { + fail("cert identified as key entry"); + } + + if (!certName.equals(store.getCertificateAlias(cert))) + { + fail("Did not return alias for certificate entry"); + } + } + + private void secretKeyStorageCheck(KeyStore store, String keyName, SecretKey key, char[] password) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException + { + if (!store.containsAlias(keyName)) + { + fail("couldn't find alias privateKey"); + } + + if (store.isCertificateEntry(keyName)) + { + fail("key identified as certificate entry"); + } + + if (!store.isKeyEntry(keyName)) + { + fail("key not identified as key entry"); + } + + Key storeKey = store.getKey(keyName, password); + + isTrue("", Arrays.areEqual(key.getEncoded(), storeKey.getEncoded())); + + if (password != null) + { + try + { + store.getKey(keyName, null); + } + catch (UnrecoverableKeyException e) + { + isTrue("", e.getMessage().startsWith("BCFKS KeyStore unable to recover secret key (seckey)")); + } + } + + Certificate[] certificateChain = store.getCertificateChain(keyName); + if (certificateChain != null) + { + fail("returned certificates!"); + } + } + + public String getName() + { + return "BCFKS"; + } + + public void performTest() + throws Exception + { + shouldCreateEmptyBCFKSNoPassword(); + shouldCreateEmptyBCFKSPassword(); + shouldStoreMultipleKeys(); + shouldStoreOneCertificate(); + shouldStoreOneECKeyWithChain(); + shouldStoreOnePrivateKey(); + shouldStoreOnePrivateKeyWithChain(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new BCFKSStoreTest()); + } +} diff -Nru bouncycastle-1.55/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java bouncycastle-1.56/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java --- bouncycastle-1.55/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java 2016-12-19 01:31:59.000000000 +0000 @@ -0,0 +1,732 @@ +package org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.util.Date; +import java.util.Enumeration; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.test.SimpleTest; + +/** + * Exercise the BCFKS KeyStore, + */ +public class BCFKSStoreTest + extends SimpleTest +{ + private static byte[] trustedCertData = Base64.decode( + "MIIB/DCCAaagAwIBAgIBATANBgkqhkiG9w0BAQQFADCBhjELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb24gb2YgdGhlIE" + + "JvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExJjAkBgkqhkiG9w0BCQEWF2lzc3VlckBi" + + "b3VuY3ljYXN0bGUub3JnMB4XDTE0MDIyODExMjcxMVoXDTE0MDQyOTExMjcxMVowgYcxCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaG" + + "UgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMScwJQYJKoZI" + + "hvcNAQkBFhhzdWJqZWN0QGJvdW5jeWNhc3RsZS5vcmcwWjANBgkqhkiG9w0BAQEFAANJADBGAkEAtKfkYXBXTxapcIKyK+WLaipil5" + + "hBm+EocqS9umJs+umQD3ar+xITnc5d5WVk+rK2VDFloEDGBoh0IOM9ke1+1wIBETANBgkqhkiG9w0BAQQFAANBAJ/ZhfF21NykhbEY" + + "RQrAo/yRr9XfpmBTVUSlLJXYoNVVRT5u9SGQqmPNfHElrTvNMZQPC0ridDZtBWb6S2tg9/E="); + + static char[] testPassword = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}; + static char[] invalidTestPassword = {'Y', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}; + + + public void shouldCreateEmptyBCFKSNoPassword() + throws Exception + { + checkEmptyStore(null); + } + + public void shouldCreateEmptyBCFKSPassword() + throws Exception + { + checkEmptyStore(testPassword); + } + + private void checkEmptyStore(char[] passwd) + throws KeyStoreException, NoSuchProviderException, IOException, NoSuchAlgorithmException, CertificateException + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + } + + private void checkInvalidLoad(KeyStore store, char[] passwd, byte[] data) + throws NoSuchAlgorithmException, CertificateException, KeyStoreException + { + checkInvalidLoadForPassword(store, invalidTestPassword, data); + + if (passwd != null) + { + checkInvalidLoadForPassword(store, null, data); + } + } + + private void checkInvalidLoadForPassword(KeyStore store, char[] password, byte[] data) + throws NoSuchAlgorithmException, CertificateException, KeyStoreException + { + try + { + store.load(new ByteArrayInputStream(data), password); + } + catch (IOException e) + { + isTrue("wrong message", "BCFKS KeyStore corrupted: MAC calculation failed.".equals(e.getMessage())); + } + + isTrue("", 0 == store.size()); + isTrue("", !store.aliases().hasMoreElements()); + } + + public void shouldStoreOneCertificate() + throws Exception + { + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + checkOneCertificate(cert, null); + checkOneCertificate(cert, testPassword); + } + + private void checkOneCertificate(X509Certificate cert, char[] passwd) + throws KeyStoreException, NoSuchProviderException, IOException, NoSuchAlgorithmException, CertificateException + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setCertificateEntry("cert", cert); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "cert".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + certStorageCheck(store1, "cert", cert); + + Date entryDate = store1.getCreationDate("cert"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", entryDate.equals(store2.getCreationDate("cert"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "cert".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + certStorageCheck(store2, "cert", cert); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("cert"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + public void shouldStoreOnePrivateKey() + throws Exception + { + PrivateKey privKey = getPrivateKey(); + + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + checkOnePrivateKeyFips(privKey, new X509Certificate[] { cert }, null); + checkOnePrivateKeyFips(privKey, new X509Certificate[] { cert }, testPassword); + checkOnePrivateKeyDef(privKey, new X509Certificate[] { cert }, null); + checkOnePrivateKeyDef(privKey, new X509Certificate[] { cert }, testPassword); + } + + public void shouldStoreOnePrivateKeyWithChain() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(512); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withRSA", + null, + kp1.getPublic()); + + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + } + + public void shouldStoreOneECKeyWithChain() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC"); + + kpGen.initialize(256); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withECDSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withECDSA", + null, + kp1.getPublic()); + + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + } + + public void shouldRejectInconsistentKeys() + throws Exception + { + PrivateKey privKey = getPrivateKey(); + + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.interCertBin)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + try + { + store1.setKeyEntry("privkey", privKey, "hello".toCharArray(), new X509Certificate[]{interCert}); + fail("no exception"); + } + catch (KeyStoreException e) + { + isTrue("", "RSA keys do not have the same modulus".equals(e.getCause().getMessage())); + } + } + + private void checkOnePrivateKeyFips(PrivateKey key, X509Certificate[] certs, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + checkOnePrivateKey(key, store1, certs, passwd); + } + + private void checkOnePrivateKeyDef(PrivateKey key, X509Certificate[] certs, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS-DEF", "BC"); + + store1.load(null, null); + + checkOnePrivateKey(key, store1, certs, passwd); + } + + private void checkOnePrivateKey(PrivateKey key, KeyStore store1, X509Certificate[] certs, char[] passwd) + throws Exception + { + store1.setKeyEntry("privkey", key, passwd, certs); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "privkey".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + privateKeyStorageCheck(store1, "privkey", key, certs[0], passwd); + + Date entryDate = store1.getCreationDate("privkey"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", store2.getCertificateChain("privkey").length == certs.length); + Certificate[] sChain = store2.getCertificateChain("privkey"); + for (int i = 0; i != sChain.length; i++) + { + isTrue("", certs[i].equals(sChain[i])); + } + isTrue("", entryDate.equals(store2.getCreationDate("privkey"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "privkey".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + privateKeyStorageCheck(store2, "privkey", key, certs[0], passwd); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("privkey"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + public void shouldStoreMultipleKeys() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(512); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withRSA", + null, + kp1.getPublic()); + + PrivateKey privKey = kp1.getPrivate(); + + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(trustedCertData)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setKeyEntry("privkey", privKey, testPassword, new X509Certificate[]{interCert, finalCert}); + store1.setCertificateEntry("trusted", cert); + SecretKeySpec aesKey = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "AES"); + store1.setKeyEntry("secret1", aesKey, "secretPwd1".toCharArray(), null); + SecretKeySpec edeKey = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "DESede"); + store1.setKeyEntry("secret2", edeKey, "secretPwd2".toCharArray(), null); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, testPassword); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), testPassword); + + isTrue("", 4 ==store2.size()); + + Key storeDesEde = store2.getKey("secret2", "secretPwd2".toCharArray()); + + isTrue("", edeKey.getAlgorithm().equals(storeDesEde.getAlgorithm())); + + isTrue("", Arrays.areEqual(edeKey.getEncoded(), storeDesEde.getEncoded())); + + Key storeAes = store2.getKey("secret1", "secretPwd1".toCharArray()); + isTrue("", Arrays.areEqual(aesKey.getEncoded(), storeAes.getEncoded())); + isTrue("", aesKey.getAlgorithm().equals(storeAes.getAlgorithm())); + + Key storePrivKey = store2.getKey("privkey", testPassword); + isTrue("", privKey.equals(storePrivKey)); + isTrue("", 2 == store2.getCertificateChain("privkey").length); + + Certificate storeCert = store2.getCertificate("trusted"); + isTrue("", cert.equals(storeCert)); + + isTrue("", null ==store2.getCertificate("unknown")); + + isTrue("", null ==store2.getCertificateChain("unknown")); + + isTrue("", !store2.isCertificateEntry("unknown")); + + isTrue("", !store2.isKeyEntry("unknown")); + + isTrue("", !store2.containsAlias("unknown")); + } + + public void shouldStoreSecretKeys() + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + SecretKeySpec aesKey = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "AES"); + SecretKeySpec edeKey1 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "DESede"); + SecretKeySpec edeKey2 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "TripleDES"); + SecretKeySpec edeKey3 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "TDEA"); + SecretKeySpec hmacKey1 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff"), "HmacSHA1"); + SecretKeySpec hmacKey224 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff"), "HmacSHA224"); + SecretKeySpec hmacKey256 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff01ff"), "HmacSHA256"); + SecretKeySpec hmacKey384 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff0102ff"), "HmacSHA384"); + SecretKeySpec hmacKey512 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff010203ff"), "HmacSHA512"); + + store1.setKeyEntry("secret1", aesKey, "secretPwd1".toCharArray(), null); + store1.setKeyEntry("secret2", edeKey1, "secretPwd2".toCharArray(), null); + store1.setKeyEntry("secret3", edeKey2, "secretPwd3".toCharArray(), null); + store1.setKeyEntry("secret4", edeKey3, "secretPwd4".toCharArray(), null); + store1.setKeyEntry("secret5", hmacKey1, "secretPwd5".toCharArray(), null); + store1.setKeyEntry("secret6", hmacKey224, "secretPwd6".toCharArray(), null); + store1.setKeyEntry("secret7", hmacKey256, "secretPwd7".toCharArray(), null); + store1.setKeyEntry("secret8", hmacKey384, "secretPwd8".toCharArray(), null); + store1.setKeyEntry("secret9", hmacKey512, "secretPwd9".toCharArray(), null); + + checkSecretKey(store1, "secret1", "secretPwd1".toCharArray(), aesKey); + checkSecretKey(store1, "secret2", "secretPwd2".toCharArray(), edeKey1); // TRIPLEDES and TDEA will convert to DESEDE + checkSecretKey(store1, "secret3", "secretPwd3".toCharArray(), edeKey1); + checkSecretKey(store1, "secret4", "secretPwd4".toCharArray(), edeKey1); + checkSecretKey(store1, "secret5", "secretPwd5".toCharArray(), hmacKey1); + checkSecretKey(store1, "secret6", "secretPwd6".toCharArray(), hmacKey224); + checkSecretKey(store1, "secret7", "secretPwd7".toCharArray(), hmacKey256); + checkSecretKey(store1, "secret8", "secretPwd8".toCharArray(), hmacKey384); + checkSecretKey(store1, "secret9", "secretPwd9".toCharArray(), hmacKey512); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, "secretkeytest".toCharArray()); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), "secretkeytest".toCharArray()); + + checkSecretKey(store2, "secret1", "secretPwd1".toCharArray(), aesKey); + checkSecretKey(store2, "secret2", "secretPwd2".toCharArray(), edeKey1); // TRIPLEDES and TDEA will convert to DESEDE + checkSecretKey(store2, "secret3", "secretPwd3".toCharArray(), edeKey1); + checkSecretKey(store2, "secret4", "secretPwd4".toCharArray(), edeKey1); + checkSecretKey(store2, "secret5", "secretPwd5".toCharArray(), hmacKey1); + checkSecretKey(store2, "secret6", "secretPwd6".toCharArray(), hmacKey224); + checkSecretKey(store2, "secret7", "secretPwd7".toCharArray(), hmacKey256); + checkSecretKey(store2, "secret8", "secretPwd8".toCharArray(), hmacKey384); + checkSecretKey(store2, "secret9", "secretPwd9".toCharArray(), hmacKey512); + + isTrue("", null ==store2.getKey("secret10", new char[0])); + } + + private void checkSecretKey(KeyStore store, String alias, char[] passwd, SecretKey key) + throws Exception + { + SecretKey sKey = (SecretKey)store.getKey(alias, passwd); + + isTrue("", Arrays.areEqual(key.getEncoded(), sKey.getEncoded())); + isTrue("", key.getAlgorithm().equals(sKey.getAlgorithm())); + + if (!store.isKeyEntry(alias)) + { + fail("key not identified as key entry"); + } + } + + private PrivateKey getPrivateKey() + { + PrivateKey privKey = null; + + RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16), + new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16), + new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16), + new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16), + new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16), + new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16), + new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16)); + + + try + { + KeyFactory fact = KeyFactory.getInstance("RSA", "BC"); + + privKey = fact.generatePrivate(privKeySpec); + } + catch (Exception e) + { + fail("error setting up keys - " + e.toString()); + } + + return privKey; + } + + public void shouldStoreOneSecretKey() + throws Exception + { + checkOneSecretKey(new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "AES"), null); + checkOneSecretKey(new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "AES"), testPassword); + } + + private void checkOneSecretKey(SecretKey key, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setKeyEntry("seckey", key, passwd, null); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "seckey".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + secretKeyStorageCheck(store1, "seckey", key, passwd); + + Date entryDate = store1.getCreationDate("seckey"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", entryDate.equals(store2.getCreationDate("seckey"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "seckey".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + secretKeyStorageCheck(store2, "seckey", key, passwd); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("seckey"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + private void privateKeyStorageCheck(KeyStore store, String keyName, PrivateKey key, Certificate cert, char[] password) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException + { + if (!store.containsAlias(keyName)) + { + fail("couldn't find alias privateKey"); + } + + if (store.isCertificateEntry(keyName)) + { + fail("key identified as certificate entry"); + } + + if (!store.isKeyEntry(keyName)) + { + fail("key not identified as key entry"); + } + + Key storeKey = store.getKey(keyName, password); + + if (store.getType().equals("BCFKS")) + { + isTrue("", key.equals(storeKey)); + } + + if (password != null) + { + try + { + store.getKey(keyName, null); + } + catch (UnrecoverableKeyException e) + { + isTrue("",e.getMessage().startsWith("BCFKS KeyStore unable to recover private key (privkey)")); + } + } + + Certificate[] certificateChain = store.getCertificateChain(keyName); + if (certificateChain == null) + { + fail("Did not return certificate chain"); + } + isTrue("", cert.equals(certificateChain[0])); + + isTrue("", keyName.equals(store.getCertificateAlias(cert))); + } + + private void certStorageCheck(KeyStore store, String certName, Certificate cert) + throws KeyStoreException + { + if (!store.containsAlias(certName)) + { + fail("couldn't find alias " + certName); + } + + if (!store.isCertificateEntry(certName)) + { + fail("cert not identified as certificate entry"); + } + + if (store.isKeyEntry(certName)) + { + fail("cert identified as key entry"); + } + + if (!certName.equals(store.getCertificateAlias(cert))) + { + fail("Did not return alias for certificate entry"); + } + } + + private void secretKeyStorageCheck(KeyStore store, String keyName, SecretKey key, char[] password) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException + { + if (!store.containsAlias(keyName)) + { + fail("couldn't find alias privateKey"); + } + + if (store.isCertificateEntry(keyName)) + { + fail("key identified as certificate entry"); + } + + if (!store.isKeyEntry(keyName)) + { + fail("key not identified as key entry"); + } + + Key storeKey = store.getKey(keyName, password); + + isTrue("", Arrays.areEqual(key.getEncoded(), storeKey.getEncoded())); + + if (password != null) + { + try + { + store.getKey(keyName, null); + } + catch (UnrecoverableKeyException e) + { + isTrue("", e.getMessage().startsWith("BCFKS KeyStore unable to recover secret key (seckey)")); + } + } + + Certificate[] certificateChain = store.getCertificateChain(keyName); + if (certificateChain != null) + { + fail("returned certificates!"); + } + } + + public String getName() + { + return "BCFKS"; + } + + public void performTest() + throws Exception + { + shouldCreateEmptyBCFKSNoPassword(); + shouldCreateEmptyBCFKSPassword(); + shouldStoreMultipleKeys(); + shouldStoreOneCertificate(); + shouldStoreOneECKeyWithChain(); + shouldStoreOnePrivateKey(); + shouldStoreOnePrivateKeyWithChain(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new BCFKSStoreTest()); + } +} diff -Nru bouncycastle-1.55/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/RSATest.java bouncycastle-1.56/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/RSATest.java --- bouncycastle-1.55/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/RSATest.java 2005-11-15 11:34:35.000000000 +0000 +++ bouncycastle-1.56/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/RSATest.java 2016-08-23 02:02:41.000000000 +0000 @@ -13,6 +13,8 @@ import java.security.spec.RSAPrivateCrtKeySpec; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; +import java.util.Set; +import java.util.HashSet; import javax.crypto.Cipher; @@ -387,6 +389,37 @@ { fail("key generation test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); } + + testGetExceptionsPKCS1(); + } + + public void testGetExceptionsPKCS1() + throws Exception + { + KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA", "BC"); + keygen.initialize(1024); + KeyPair keypair = keygen.genKeyPair(); + SecureRandom rand = new SecureRandom(); + Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC"); + byte[] ciphertext = new byte[1024 / 8]; + HashSet exceptions = new HashSet(); + final int SAMPLES = 1000; + for (int i = 0; i < SAMPLES; i++) + { + rand.nextBytes(ciphertext); + ciphertext[0] = (byte)0; + try + { + c.init(Cipher.DECRYPT_MODE, keypair.getPrivate()); + c.doFinal(ciphertext); + } + catch (Exception ex) + { + String message = ex.toString(); + exceptions.add(message); + } + } + isTrue("exception count wrong", 1 == exceptions.size()); } public String getName() diff -Nru bouncycastle-1.55/README.md bouncycastle-1.56/README.md --- bouncycastle-1.55/README.md 2015-11-08 01:58:19.000000000 +0000 +++ bouncycastle-1.56/README.md 2016-12-22 08:01:13.000000000 +0000 @@ -25,6 +25,8 @@ The **pg** module is the home for code used to support OpenPGP. +The **tls** module is the home for code used to a general TLS API and JSSE Provider (as at 1.56 this should be considered a beta). + The build scripts that come with the full distribution allow creation of the different releases by using the different source trees while excluding classes that are not appropriate and copying in the required compatibility classes from the directories containing compatibility classes appropriate for the distribution. If you want to try create a build for yourself, using your own environment, the best way to do it is to start with the build for the distribution you are interested in, make sure that builds, and then modify your build scripts to do the required exclusions and file copies for your setup, otherwise you are likely to get class not found exceptions. The final caveat to this is that as the j2me distribution includes some compatibility classes starting in the java package, you need to use an obfuscator to change the package names before attempting to import a midlet using the BC API. @@ -71,4 +73,4 @@ ## Finally -Enjoy! \ No newline at end of file +Enjoy! diff -Nru bouncycastle-1.55/scripts/jdk1.1ed.sh bouncycastle-1.56/scripts/jdk1.1ed.sh --- bouncycastle-1.55/scripts/jdk1.1ed.sh 2016-08-16 00:25:12.000000000 +0000 +++ bouncycastle-1.56/scripts/jdk1.1ed.sh 2016-12-20 01:53:07.000000000 +0000 @@ -154,3 +154,33 @@ w q % + +ed org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java <<% +g/private final .*;/s/final// +w +q +% + +ed org/bouncycastle/jcajce/spec/AEADParameterSpec.java <<% +g/private final .*;/s/final// +w +q +% + +ed org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java <<% +g/private final .*;/s/final// +w +q +% + +ed org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java <<% +g/private final .*;/s/final// +w +q +% + +ed org/bouncycastle/cert/dane/DANEEntry.java <<% +g/private final .*;/s/final// +w +q +% diff -Nru bouncycastle-1.55/scripts/jdk1.2ed.sh bouncycastle-1.56/scripts/jdk1.2ed.sh --- bouncycastle-1.55/scripts/jdk1.2ed.sh 2015-10-07 21:50:37.000000000 +0000 +++ bouncycastle-1.56/scripts/jdk1.2ed.sh 2016-12-20 01:53:07.000000000 +0000 @@ -24,3 +24,9 @@ w q % + +ed org/bouncycastle/util/test/FixedSecureRandom.java <<% +g/private static final boolean/s/final// +w +q +% diff -Nru bouncycastle-1.55/settings.gradle bouncycastle-1.56/settings.gradle --- bouncycastle-1.55/settings.gradle 2013-06-08 23:52:49.000000000 +0000 +++ bouncycastle-1.56/settings.gradle 2016-10-28 21:59:53.000000000 +0000 @@ -3,3 +3,4 @@ include "pg" include "pkix" include "prov" +include "tls" diff -Nru bouncycastle-1.55/tls/build.gradle bouncycastle-1.56/tls/build.gradle --- bouncycastle-1.55/tls/build.gradle 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/build.gradle 2016-11-13 00:33:38.000000000 +0000 @@ -0,0 +1,15 @@ +dependencies { + compile project(':core') + compile project(':prov') +} + +jar.baseName = "bctls-jdk15on" + +cobertura { + coverageDirs = [ + "${rootProject.projectDir}/core/build/classes/main", + "${rootProject.projectDir}/prov/build/classes/main", + "${rootProject.projectDir}/tls/build/classes/main" + ] +} + diff -Nru bouncycastle-1.55/tls/src/main/j2me/org/bouncycastle/tls/UDPTransport.java bouncycastle-1.56/tls/src/main/j2me/org/bouncycastle/tls/UDPTransport.java --- bouncycastle-1.55/tls/src/main/j2me/org/bouncycastle/tls/UDPTransport.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/j2me/org/bouncycastle/tls/UDPTransport.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,107 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import javax.microedition.io.DatagramConnection; +import javax.microedition.io.Datagram; + +public class UDPTransport + implements DatagramTransport +{ + + protected final static int MIN_IP_OVERHEAD = 20; + protected final static int MAX_IP_OVERHEAD = MIN_IP_OVERHEAD + 64; + protected final static int UDP_OVERHEAD = 8; + + protected final DatagramConnection socket; + protected final int receiveLimit, sendLimit; + + public UDPTransport(DatagramConnection socket, int mtu) + throws IOException + { + // + // In 1.3 and earlier sockets were bound and connected during creation + // + //if (!socket.isBound() || !socket.isConnected()) + //{ + // throw new IllegalArgumentException("'socket' must be bound and connected"); + //} + + this.socket = socket; + + // NOTE: As of JDK 1.6, can use NetworkInterface.getMTU + + this.receiveLimit = mtu - MIN_IP_OVERHEAD - UDP_OVERHEAD; + this.sendLimit = mtu - MAX_IP_OVERHEAD - UDP_OVERHEAD; + } + + public int getReceiveLimit() + { + return receiveLimit; + } + + public int getSendLimit() + { + // TODO[DTLS] Implement Path-MTU discovery? + return sendLimit; + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + //socket.setSoTimeout(waitMillis); -- not applicable + + if (off == 0) + { + Datagram packet = socket.newDatagram(buf, len); + socket.receive(packet); + + return packet.getLength(); + } + else + { + byte[] rv = new byte[len]; + + Datagram packet = socket.newDatagram(rv, len); + socket.receive(packet); + + System.arraycopy(rv, 0, buf, off, packet.getLength()); + + return packet.getLength(); + } + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + if (len > getSendLimit()) + { + /* + * RFC 4347 4.1.1. "If the application attempts to send a record larger than the MTU, + * the DTLS implementation SHOULD generate an error, thus avoiding sending a packet + * which will be fragmented." + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + if (off == 0) + { + Datagram packet = socket.newDatagram(buf, len); + socket.send(packet); + } + else + { + byte[] data = new byte[len]; + + System.arraycopy(buf, off, data, 0, len); + + Datagram packet = socket.newDatagram(data, len); + socket.send(packet); + } + } + + public void close() + throws IOException + { + socket.close(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java 2016-12-16 22:32:33.000000000 +0000 @@ -0,0 +1,363 @@ +package org.bouncycastle.jsse.provider; + +import java.security.GeneralSecurityException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider; +import org.bouncycastle.util.Strings; + +public class BouncyCastleJsseProvider + extends Provider +{ + private static String info = "Bouncy Castle JSSE Provider Beta Version"; + + public static final String PROVIDER_NAME = "BCJSSE"; + + private static final double version = 0.9; + + private Map serviceMap = new HashMap(); + private Map creatorMap = new HashMap(); + + private boolean isInFipsMode; + + public BouncyCastleJsseProvider() + { + super(PROVIDER_NAME, version, info); + + configure(false, new JcaTlsCryptoProvider()); + } + + public BouncyCastleJsseProvider(Provider provider) + { + this(false, provider); + } + + public BouncyCastleJsseProvider(boolean isInFipsMode, Provider provider) + { + super(PROVIDER_NAME, version, info); + + configure(isInFipsMode, new JcaTlsCryptoProvider().setProvider(provider)); + } + + public BouncyCastleJsseProvider(String config) + { + super(PROVIDER_NAME, version, info); + + boolean isFips = false; + + try + { + if (config.indexOf(':') > 0) + { + isFips = config.substring(0, config.indexOf(':')).trim().equalsIgnoreCase("fips"); + + String cryptoName = config.substring(config.indexOf(':') + 1).trim(); + + configure(isFips, createCryptoProvider(cryptoName)); + } + else + { + configure(isFips, createCryptoProvider(config.trim())); + } + } + catch (GeneralSecurityException e) + { + throw new IllegalArgumentException("unable to set up TlsCrypto: " + e.getMessage(), e); + } + } + + public BouncyCastleJsseProvider(boolean fipsMode, JcaTlsCryptoProvider tlsCryptoProvider) + { + super(PROVIDER_NAME, version, info); + + configure(fipsMode, tlsCryptoProvider); + } + + private JcaTlsCryptoProvider createCryptoProvider(String cryptoName) + throws GeneralSecurityException + { + if (cryptoName.equalsIgnoreCase("default")) + { + return new JcaTlsCryptoProvider(); + } + else + { + Provider provider = Security.getProvider(cryptoName); + + if (provider != null) + { + return new JcaTlsCryptoProvider().setProvider(provider); + } + else + { + try + { + Class cryptoProviderClass = Class.forName(cryptoName); + + // the TlsCryptoProvider/Provider class named requires a no-args constructor + Object o = cryptoProviderClass.newInstance(); + if (o instanceof JcaTlsCryptoProvider) + { + return (JcaTlsCryptoProvider)o; + } + if (o instanceof Provider) + { + provider = (Provider)o; + + return new JcaTlsCryptoProvider().setProvider(provider); + } + + throw new IllegalArgumentException("unrecognized class: " + cryptoName); + } + catch (ClassNotFoundException e) + { + throw new IllegalArgumentException("unable to find Provider/TlsCrypto class: " + cryptoName); + } + catch (InstantiationException e) + { + throw new IllegalArgumentException("unable to create Provider/TlsCrypto class '" + cryptoName + "': " + e.getMessage(), e); + } + catch (IllegalAccessException e) + { + throw new IllegalArgumentException("unable to create Provider/TlsCrypto class '" + cryptoName + "': " + e.getMessage(), e); + } + } + } + } + + // TODO: add a real fips mode + private void configure(boolean isInFipsMode, final JcaTlsCryptoProvider baseCryptoProvider) + { + this.isInFipsMode = isInFipsMode; + + // TODO[jsse]: should X.509 be an alias. + addAlgorithmImplementation("KeyManagerFactory.X.509", "org.bouncycastle.jsse.provider.KeyManagerFactory", new EngineCreator() + { + public Object createInstance(Object constructorParameter) + { + return new ProvKeyManagerFactorySpi(); + } + }); + addAlias("Alg.Alias.KeyManagerFactory.X509", "X.509"); + addAlias("Alg.Alias.KeyManagerFactory.PKIX", "X.509"); + + addAlgorithmImplementation("TrustManagerFactory.PKIX", "org.bouncycastle.jsse.provider.TrustManagerFactory", new EngineCreator() + { + public Object createInstance(Object constructorParameter) + { + return new ProvTrustManagerFactorySpi(baseCryptoProvider.getPkixProvider()); + } + }); + addAlias("Alg.Alias.TrustManagerFactory.X.509", "PKIX"); + addAlias("Alg.Alias.TrustManagerFactory.X509", "PKIX"); + + if (isInFipsMode == false) + { + addAlgorithmImplementation("SSLContext.SSL", "org.bouncycastle.jsse.provider.SSLContext.TLS", new EngineCreator() + { + public Object createInstance(Object constructorParameter) + { + return new ProvSSLContextSpi(baseCryptoProvider); + } + }); + } + + addAlgorithmImplementation("SSLContext.TLS", "org.bouncycastle.jsse.provider.SSLContext.TLS", new EngineCreator() + { + public Object createInstance(Object constructorParameter) + { + return new ProvSSLContextSpi(baseCryptoProvider); + } + }); + addAlgorithmImplementation("SSLContext.TLSv1", "org.bouncycastle.jsse.provider.SSLContext.TLS.1", new EngineCreator() + { + public Object createInstance(Object constructorParameter) + { + return new ProvSSLContextSpi(baseCryptoProvider); + } + }); + addAlgorithmImplementation("SSLContext.Default", "org.bouncycastle.jsse.provider.SSLContext.TLS.Default", new EngineCreator() + { + public Object createInstance(Object constructorParameter) + { + return new ProvSSLContextSpi(baseCryptoProvider); + } + }); + } + + void addAttribute(String key, String attributeName, String attributeValue) + { + String attributeKey = key + " " + attributeName; + if (containsKey(attributeKey)) + { + throw new IllegalStateException("duplicate provider attribute key (" + attributeKey + ") found"); + } + + put(attributeKey, attributeValue); + } + + void addAlgorithmImplementation(String key, String className, EngineCreator creator) + { + if (containsKey(key)) + { + throw new IllegalStateException("duplicate provider key (" + key + ") found"); + } + + addAttribute(key, "ImplementedIn", "Software"); + + put(key, className); + creatorMap.put(className, creator); + } + + void addAlias(String key, String value) + { + if (containsKey(key)) + { + throw new IllegalStateException("duplicate provider key (" + key + ") found"); + } + + put(key, value); + } + + public synchronized final Provider.Service getService(String type, String algorithm) + { + String upperCaseAlgName = Strings.toUpperCase(algorithm); + + BcJsseService service = serviceMap.get(type + "." + upperCaseAlgName); + + if (service == null) + { + String aliasString = "Alg.Alias." + type + "."; + String realName = (String)this.get(aliasString + upperCaseAlgName); + + if (realName == null) + { + realName = upperCaseAlgName; + } + + String className = (String)this.get(type + "." + realName); + + if (className == null) + { + return null; + } + + String attributeKeyStart = type + "." + upperCaseAlgName + " "; + + List aliases = new ArrayList(); + Map attributes = new HashMap(); + + for (Object key : this.keySet()) + { + String sKey = (String)key; + if (sKey.startsWith(aliasString)) + { + if (this.get(key).equals(algorithm)) + { + aliases.add(sKey.substring(aliasString.length())); + } + } + if (sKey.startsWith(attributeKeyStart)) + { + attributes.put(sKey.substring(attributeKeyStart.length()), (String)this.get(sKey)); + } + } + + service = new BcJsseService(this, type, upperCaseAlgName, className, aliases, getAttributeMap(attributes), creatorMap.get(className)); + + serviceMap.put(type + "." + upperCaseAlgName, service); + } + + return service; + } + + public synchronized final Set getServices() + { + Set serviceSet = super.getServices(); + Set bcServiceSet = new HashSet(); + + for (Provider.Service service: serviceSet) + { + bcServiceSet.add(getService(service.getType(), service.getAlgorithm())); + } + + return bcServiceSet; + } + + private static final Map, Map > attributeMaps = new HashMap, Map>(); + + private static Map getAttributeMap(Map attributeMap) + { + Map attrMap = attributeMaps.get(attributeMap); + if (attrMap != null) + { + return attrMap; + } + + attributeMaps.put(attributeMap, attributeMap); + + return attributeMap; + } + + public boolean isFipsMode() + { + return isInFipsMode; + } + + private static class BcJsseService + extends Provider.Service + { + private final EngineCreator creator; + + /** + * Construct a new service. + * + * @param provider the provider that offers this service + * @param type the type of this service + * @param algorithm the algorithm name + * @param className the name of the class implementing this service + * @param aliases List of aliases or null if algorithm has no aliases + * @param attributes Map of attributes or null if this implementation + * has no attributes + * @throws NullPointerException if provider, type, algorithm, or + * className is null + */ + public BcJsseService(Provider provider, String type, String algorithm, String className, List aliases, Map attributes, EngineCreator creator) + { + super(provider, type, algorithm, className, aliases, attributes); + this.creator = creator; + } + + public Object newInstance(Object constructorParameter) + throws NoSuchAlgorithmException + { + try + { + Object instance = creator.createInstance(constructorParameter); + + if (instance == null) + { + throw new NoSuchAlgorithmException("No such algorithm in FIPS approved mode: " + getAlgorithm()); + } + + return instance; + } + catch (NoSuchAlgorithmException e) + { + throw e; + } + catch (Exception e) + { + throw new NoSuchAlgorithmException("Unable to invoke creator for " + getAlgorithm() + ": " + e.getMessage(), e); + } + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/CallbackUtil.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/CallbackUtil.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/CallbackUtil.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/CallbackUtil.java 2016-11-06 20:28:00.000000000 +0000 @@ -0,0 +1,26 @@ +package org.bouncycastle.jsse.provider; + +abstract class CallbackUtil +{ + static void safeCallback(Runnable r) + { + try + { + r.run(); + } + catch (Error e) + { + /* + * "An Error is a subclass of Throwable that indicates serious problems that a + * reasonable application should not try to catch. Most such errors are abnormal + * conditions. The ThreadDeath error, though a "normal" condition, is also a subclass of + * Error because most applications should not try to catch it." + */ + throw e; + } + catch (Throwable t) + { + // TODO[jsse] Logging + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ContextData.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ContextData.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ContextData.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ContextData.java 2016-11-21 00:44:31.000000000 +0000 @@ -0,0 +1,50 @@ +package org.bouncycastle.jsse.provider; + +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import org.bouncycastle.tls.crypto.TlsCrypto; + +final class ContextData +{ + private final TlsCrypto crypto; + private final X509KeyManager km; + private final X509TrustManager tm; + private final ProvSSLSessionContext clientSessionContext; + private final ProvSSLSessionContext serverSessionContext; + + ContextData(TlsCrypto crypto, X509KeyManager km, X509TrustManager tm, ProvSSLSessionContext clientSessionContext, + ProvSSLSessionContext serverSessionContext) + { + this.crypto = crypto; + this.km = km; + this.tm = tm; + this.clientSessionContext = clientSessionContext; + this.serverSessionContext = serverSessionContext; + } + + ProvSSLSessionContext getClientSessionContext() + { + return clientSessionContext; + } + + TlsCrypto getCrypto() + { + return crypto; + } + + X509KeyManager getKeyManager() + { + return km; + } + + ProvSSLSessionContext getServerSessionContext() + { + return serverSessionContext; + } + + X509TrustManager getTrustManager() + { + return tm; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/EngineCreator.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/EngineCreator.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/EngineCreator.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/EngineCreator.java 2016-06-07 02:08:26.000000000 +0000 @@ -0,0 +1,9 @@ +package org.bouncycastle.jsse.provider; + +import java.security.NoSuchAlgorithmException; + +interface EngineCreator +{ + Object createInstance(Object constructorParameter) + throws NoSuchAlgorithmException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/HandshakeCompletedListenerAdapter.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/HandshakeCompletedListenerAdapter.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/HandshakeCompletedListenerAdapter.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/HandshakeCompletedListenerAdapter.java 2016-09-26 00:53:43.000000000 +0000 @@ -0,0 +1,38 @@ +package org.bouncycastle.jsse.provider; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; + +class HandshakeCompletedListenerAdapter + implements HandshakeCompletedListener +{ + protected final HandshakeCompletedListener listener; + + HandshakeCompletedListenerAdapter(HandshakeCompletedListener listener) + { + this.listener = listener; + } + + public void handshakeCompleted(final HandshakeCompletedEvent event) + { + CallbackUtil.safeCallback(new Runnable(){ + public void run() + { + listener.handshakeCompleted(event); + } + }); + } + + @Override + public boolean equals(Object obj) + { + return (obj instanceof HandshakeCompletedListenerAdapter) + && ((HandshakeCompletedListenerAdapter)obj).listener == listener; + } + + @Override + public int hashCode() + { + return System.identityHashCode(listener); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java 2016-11-21 00:44:31.000000000 +0000 @@ -0,0 +1,222 @@ +package org.bouncycastle.jsse.provider; + +import java.io.IOException; +import java.security.Principal; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; +import org.bouncycastle.jcajce.util.JcaJceHelper; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.KeyExchangeAlgorithm; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCertificate; + +class JsseUtils +{ + protected static X509Certificate[] EMPTY_CHAIN = new X509Certificate[0]; + + static boolean contains(String[] values, String value) + { + for (int i = 0; i < values.length; ++i) + { + if (value.equals(values[i])) + { + return true; + } + } + return false; + } + + public static String getAuthType(int keyExchangeAlgorithm) throws IOException + { + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DH_anon: + return "DH_anon"; + case KeyExchangeAlgorithm.DH_DSS: + return "DH_DSS"; + case KeyExchangeAlgorithm.DH_RSA: + return "DH_RSA"; + case KeyExchangeAlgorithm.DHE_DSS: + return "DHE_DSS"; + case KeyExchangeAlgorithm.DHE_PSK: + return "DHE_PSK"; + case KeyExchangeAlgorithm.DHE_RSA: + return "DHE_RSA"; + case KeyExchangeAlgorithm.ECDH_anon: + return "ECDH_anon"; + case KeyExchangeAlgorithm.ECDH_ECDSA: + return "ECDH_ECDSA"; + case KeyExchangeAlgorithm.ECDH_RSA: + return "ECDH_RSA"; + case KeyExchangeAlgorithm.ECDHE_ECDSA: + return "ECDHE_ECDSA"; + case KeyExchangeAlgorithm.ECDHE_PSK: + return "ECDHE_PSK"; + case KeyExchangeAlgorithm.ECDHE_RSA: + return "ECDHE_RSA"; + case KeyExchangeAlgorithm.RSA: + return "RSA"; + case KeyExchangeAlgorithm.RSA_PSK: + return "RSA_PSK"; + case KeyExchangeAlgorithm.SRP: + return "SRP"; + case KeyExchangeAlgorithm.SRP_DSS: + return "SRP_DSS"; + case KeyExchangeAlgorithm.SRP_RSA: + return "SRP_RSA"; + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static Certificate getCertificateMessage(TlsCrypto crypto, X509Certificate[] chain) throws IOException + { + if (chain == null || chain.length < 1) + { + return Certificate.EMPTY_CHAIN; + } + + TlsCertificate[] certificateList = new TlsCertificate[chain.length]; + try + { + for (int i = 0; i < chain.length; ++i) + { + // TODO[jsse] Prefer an option that will not re-encode for typical use-cases + certificateList[i] = crypto.createCertificate(chain[i].getEncoded()); + } + } + catch (CertificateEncodingException e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + + return new Certificate(certificateList); + } + + public static String getClientAuthType(short clientCertificateType) throws IOException + { + switch (clientCertificateType) + { + case ClientCertificateType.dss_sign: + return "DSA"; + case ClientCertificateType.ecdsa_sign: + // TODO[jsse] Seems to be what SunJSSE forwards to KeyManager.chooseClientAlias + return "EC"; + case ClientCertificateType.rsa_sign: + return "RSA"; + + // TODO[jsse] "fixed" types and any others + + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static X509Certificate[] getX509CertificateChain(Certificate certificateMessage) + { + if (certificateMessage == null || certificateMessage.isEmpty()) + { + return EMPTY_CHAIN; + } + + // TODO[jsse] Consider provider-related issues + JcaJceHelper helper = new DefaultJcaJceHelper(); + + try + { + X509Certificate[] chain = new X509Certificate[certificateMessage.getLength()]; + for (int i = 0; i < chain.length; ++i) + { + chain[i] = JcaTlsCertificate.convert(certificateMessage.getCertificateAt(i), helper).getX509Certificate(); + } + return chain; + } + catch (IOException e) + { + // TODO[jsse] Logging + throw new RuntimeException(e); + } + } + + public static X500Principal getSubject(Certificate certificateMessage) + { + if (certificateMessage == null || certificateMessage.isEmpty()) + { + return null; + } + + // TODO[jsse] Consider provider-related issues + JcaJceHelper helper = new DefaultJcaJceHelper(); + + try + { + return JcaTlsCertificate.convert(certificateMessage.getCertificateAt(0), helper).getX509Certificate() + .getSubjectX500Principal(); + } + catch (IOException e) + { + // TODO[jsse] Logging + throw new RuntimeException(e); + } + } + + static Set toX500Principals(X500Name[] names) throws IOException + { + if (names == null || names.length == 0) + { + return Collections.emptySet(); + } + + Set principals = new HashSet(names.length); + + for (int i = 0; i < names.length; ++i) + { + X500Name name = names[i]; + if (name != null) + { + principals.add(new X500Principal(name.getEncoded(ASN1Encoding.DER))); + } + } + + return principals; + } + + static Set toX500Names(Principal[] principals) + { + if (principals == null || principals.length == 0) + { + return Collections.emptySet(); + } + + Set names = new HashSet(principals.length); + + for (int i = 0; i != principals.length; i++) + { + Principal principal = principals[i]; + if (principal instanceof X500Principal) + { + names.add(X500Name.getInstance(((X500Principal)principal).getEncoded())); + } + else if (principal != null) + { + // TODO[jsse] Should we really be trying to support these? + names.add(new X500Name(principal.getName())); // hope for the best + } + } + + return names; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvExtendedSSLSession.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvExtendedSSLSession.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvExtendedSSLSession.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvExtendedSSLSession.java 2016-12-09 03:32:31.000000000 +0000 @@ -0,0 +1,151 @@ +package org.bouncycastle.jsse.provider; + +import java.security.Principal; +import java.security.cert.Certificate; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.ExtendedSSLSession; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSessionContext; + +// TODO[jsse] Serializable ? +class ProvExtendedSSLSession + extends ExtendedSSLSession +{ + // TODO[jsse] Ensure this behaves according to the javadoc for SSLSocket.getSession and SSLEngine.getSession + protected final static ProvExtendedSSLSession NULL_SESSION = new ProvExtendedSSLSession(ProvSSLSession.NULL_SESSION); + + protected final Map valueMap = Collections.synchronizedMap(new HashMap()); + + private final ProvSSLSession sslSession; + + ProvExtendedSSLSession(ProvSSLSession sslSession) + { + this.sslSession = sslSession; + } + + public int getApplicationBufferSize() + { + throw new UnsupportedOperationException(); + } + + public String getCipherSuite() + { + return sslSession.getCipherSuite(); + } + + public long getCreationTime() + { + return sslSession.getCreationTime(); + } + + public byte[] getId() + { + return sslSession.getId(); + } + + public long getLastAccessedTime() + { + return sslSession.getLastAccessedTime(); + } + + public Certificate[] getLocalCertificates() + { + return sslSession.getLocalCertificates(); + } + + public Principal getLocalPrincipal() + { + return sslSession.getLocalPrincipal(); + } + + @Override + public String[] getLocalSupportedSignatureAlgorithms() + { + throw new UnsupportedOperationException(); + } + + public int getPacketBufferSize() + { + return sslSession.getPacketBufferSize(); + } + + public javax.security.cert.X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException + { + return sslSession.getPeerCertificateChain(); + } + + public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException + { + return sslSession.getPeerCertificates(); + } + + public String getPeerHost() + { + return sslSession.getPeerHost(); + } + + public int getPeerPort() + { + return sslSession.getPeerPort(); + } + + public Principal getPeerPrincipal() throws SSLPeerUnverifiedException + { + return sslSession.getPeerPrincipal(); + } + + public String[] getPeerSupportedSignatureAlgorithms() + { + throw new UnsupportedOperationException(); + } + + public String getProtocol() + { + return sslSession.getProtocol(); + } + + // TODO: SSNIServerName post 1.7 + public List getRequestedServerNames() + { + throw new UnsupportedOperationException(); + } + + public SSLSessionContext getSessionContext() + { + return sslSession.getSessionContext(); + } + + public Object getValue(String name) + { + return sslSession.getValue(name); + } + + public String[] getValueNames() + { + return sslSession.getValueNames(); + } + + public void invalidate() + { + sslSession.invalidate(); + } + + public boolean isValid() + { + return sslSession.isValid(); + } + + public void putValue(String name, Object value) + { + sslSession.putValue(name, value); + } + + public void removeValue(String name) + { + sslSession.removeValue(name); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvKeyManagerFactorySpi.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvKeyManagerFactorySpi.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvKeyManagerFactorySpi.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvKeyManagerFactorySpi.java 2016-09-15 00:36:52.000000000 +0000 @@ -0,0 +1,63 @@ +package org.bouncycastle.jsse.provider; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.util.Collections; +import java.util.List; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactorySpi; +import javax.net.ssl.KeyStoreBuilderParameters; +import javax.net.ssl.ManagerFactoryParameters; + +class ProvKeyManagerFactorySpi + extends KeyManagerFactorySpi +{ + // at the moment we're only accepting X.509/PKCS#8 key material so there is only one key manager needed + KeyManager keyManager; + + protected void engineInit(KeyStore keyStore, char[] passwd) + throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException + { + if (keyStore == null) + { + keyManager = new ProvX509KeyManager(Collections.emptyList()); + } + else + { + try + { + KeyStore.Builder builder = KeyStore.Builder.newInstance(keyStore, new KeyStore.PasswordProtection(passwd)); + keyManager = new ProvX509KeyManager(Collections.singletonList(builder)); + } + catch (RuntimeException e) + { + throw new KeyStoreException("initialization failed", e); + } + } + } + + protected void engineInit(ManagerFactoryParameters managerFactoryParameters) + throws InvalidAlgorithmParameterException + { + if (managerFactoryParameters instanceof KeyStoreBuilderParameters) + { + List builders = ((KeyStoreBuilderParameters)managerFactoryParameters).getParameters(); + keyManager = new ProvX509KeyManager(builders); + } + + throw new InvalidAlgorithmParameterException("Parameters must be instance of KeyStoreBuilderParameters"); + } + + protected KeyManager[] engineGetKeyManagers() + { + if (keyManager != null) + { + return new KeyManager[] { keyManager }; + } + throw new IllegalStateException("KeyManagerFactory not initialized"); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java 2016-12-09 02:39:57.000000000 +0000 @@ -0,0 +1,399 @@ +package org.bouncycastle.jsse.provider; + +import java.security.GeneralSecurityException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContextSpi; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import org.bouncycastle.tls.CipherSuite; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsCryptoProvider; + +class ProvSSLContextSpi + extends SSLContextSpi +{ + private static final Map supportedCipherSuites = createSupportedCipherSuites(); + private static final Map supportedProtocols = createSupportedProtocols(); + + private static Map createSupportedCipherSuites() + { + Map cs = new HashMap(); + + cs.put("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256); + cs.put("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384); + cs.put("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384); + cs.put("TLS_ECDHE_ECDSA_WITH_AES_256_CBC", CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA); + cs.put("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256); + cs.put("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256); + cs.put("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA); + + cs.put("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256); + cs.put("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384); + cs.put("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384); + cs.put("TLS_ECDHE_RSA_WITH_AES_256_CBC", CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA); + cs.put("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256); + cs.put("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256); + cs.put("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA); + + cs.put("TLS_RSA_WITH_AES_256_GCM_SHA384", CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384); + cs.put("TLS_RSA_WITH_AES_256_CBC_SHA384", CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256); + cs.put("TLS_RSA_WITH_AES_256_CBC", CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA); + cs.put("TLS_RSA_WITH_AES_128_GCM_SHA256", CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256); + cs.put("TLS_RSA_WITH_AES_128_CBC_SHA256", CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256); + cs.put("TLS_RSA_WITH_AES_128_CBC_SHA", CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA); + + return Collections.unmodifiableMap(cs); + } + + private static Map createSupportedProtocols() + { + Map ps = new HashMap(); +// ps.put("SSLv3", ProtocolVersion.SSLv3); + ps.put("TLSv1", ProtocolVersion.TLSv10); + ps.put("TLSv1.1", ProtocolVersion.TLSv11); + ps.put("TLSv1.2", ProtocolVersion.TLSv12); + return Collections.unmodifiableMap(ps); + } + + protected final TlsCryptoProvider cryptoProvider; + + protected boolean initialized = false; + + private TlsCrypto crypto; + private X509KeyManager km; + private X509TrustManager tm; + private ProvSSLSessionContext clientSessionContext; + private ProvSSLSessionContext serverSessionContext; + + ProvSSLContextSpi(TlsCryptoProvider cryptoProvider) + { + this.cryptoProvider = cryptoProvider; + } + + int[] convertCipherSuites(String[] suites) + { + int[] result = new int[suites.length]; + for (int i = 0; i < suites.length; ++i) + { + result[i] = supportedCipherSuites.get(suites[i]); + } + return result; + } + + ProvSSLSessionContext createSSLSessionContext() + { + return new ProvSSLSessionContext(this); + } + + String getCipherSuiteString(int suite) + { + if (TlsUtils.isValidUint16(suite)) + { + for (Map.Entry entry : supportedCipherSuites.entrySet()) + { + if (entry.getValue().intValue() == suite) + { + return entry.getKey(); + } + } + } + return null; + } + + String[] getDefaultCipherSuites() + { + return new String[]{ + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + }; + } + + String[] getDefaultProtocols() + { + return new String[]{ "TLSv1.2" }; + } + + ProtocolVersion getMaximumVersion(String[] protocols) + { + ProtocolVersion max = null; + if (protocols != null) + { + for (String protocol : protocols) + { + if (protocol != null) + { + ProtocolVersion v = supportedProtocols.get(protocol); + if (v != null && (max == null || v.isLaterVersionOf(max))) + { + max = v; + } + } + } + } + return max; + } + + ProtocolVersion getMinimumVersion(String[] protocols) + { + ProtocolVersion min = null; + if (protocols != null) + { + for (String protocol : protocols) + { + if (protocol != null) + { + ProtocolVersion v = supportedProtocols.get(protocol); + if (v != null && (min == null || min.isLaterVersionOf(v))) + { + min = v; + } + } + } + } + return min; + } + + String getProtocolString(ProtocolVersion v) + { + if (v != null) + { + for (Map.Entry entry : supportedProtocols.entrySet()) + { + if (v.equals(entry.getValue())) + { + return entry.getKey(); + } + } + } + return null; + } + + String[] getSupportedCipherSuites() + { + return supportedCipherSuites.keySet().toArray(new String[supportedCipherSuites.size()]); + } + + String[] getSupportedProtocols() + { + return supportedProtocols.keySet().toArray(new String[supportedProtocols.size()]); + } + + boolean isSupportedCipherSuites(String[] suites) + { + if (suites == null) + { + return false; + } + for (String suite : suites) + { + if (suite == null || !supportedCipherSuites.containsKey(suite)) + { + return false; + } + } + return true; + } + + boolean isSupportedProtocols(String[] protocols) + { + if (protocols == null) + { + return false; + } + for (String protocol : protocols) + { + if (protocol == null || !supportedProtocols.containsKey(protocol)) + { + return false; + } + } + return true; + } + + protected void checkInitialized() + { + if (!initialized) + { + throw new IllegalStateException("SSLContext has not been initialized."); + } + } + + @Override + protected synchronized SSLEngine engineCreateSSLEngine() + { + checkInitialized(); + return new ProvSSLEngine(this, createContextData()); + } + + @Override + protected synchronized SSLEngine engineCreateSSLEngine(String host, int port) + { + checkInitialized(); + return new ProvSSLEngine(this, createContextData(), host, port); + } + + @Override + protected synchronized SSLSessionContext engineGetClientSessionContext() + { + return clientSessionContext; + } + + @Override + protected SSLParameters engineGetDefaultSSLParameters() + { + // TODO[jsse] Review initial values + SSLParameters r = new SSLParameters(); + r.setCipherSuites(getDefaultCipherSuites()); + r.setProtocols(getDefaultProtocols()); + return r; + } + + @Override + protected synchronized SSLSessionContext engineGetServerSessionContext() + { + return serverSessionContext; + } + + @Override + protected SSLServerSocketFactory engineGetServerSocketFactory() + { + checkInitialized(); + return new ProvSSLServerSocketFactory(this); + } + + @Override + protected SSLSocketFactory engineGetSocketFactory() + { + checkInitialized(); + return new ProvSSLSocketFactory(this); + } + + @Override + protected SSLParameters engineGetSupportedSSLParameters() + { + // TODO[jsse] Review initial values + SSLParameters r = new SSLParameters(); + r.setCipherSuites(getSupportedCipherSuites()); + r.setProtocols(getSupportedProtocols()); + return r; + } + + @Override + protected synchronized void engineInit(KeyManager[] kms, TrustManager[] tms, SecureRandom sr) throws KeyManagementException + { + this.initialized = false; + this.crypto = cryptoProvider.create(sr); + this.km = selectKeyManager(kms); + this.tm = selectTrustManager(tms); + this.clientSessionContext = createSSLSessionContext(); + this.serverSessionContext = createSSLSessionContext(); + this.initialized = true; + } + + protected ContextData createContextData() + { + return new ContextData(crypto, km, tm, clientSessionContext, serverSessionContext); + } + + protected X509KeyManager findX509KeyManager(KeyManager[] kms) + { + if (kms != null) + { + for (KeyManager km : kms) + { + if (km instanceof X509KeyManager) + { + return (X509KeyManager)km; + } + } + } + return null; + } + + protected X509TrustManager findX509TrustManager(TrustManager[] tms) + { + if (tms != null) + { + for (TrustManager tm : tms) + { + if (tm instanceof X509TrustManager) + { + return (X509TrustManager)tm; + } + } + } + return null; + } + + protected X509KeyManager selectKeyManager(KeyManager[] kms) throws KeyManagementException + { + if (kms == null) + { + try + { + /* + * "[...] the installed security providers will be searched for the highest priority + * implementation of the appropriate factory." + */ + + // TODO[jsse] Is PKIX a reasonable algorithm to use here? + KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); + // TODO[jsse] Is this supported generally? + kmf.init(null, null); + kms = kmf.getKeyManagers(); + } + catch (GeneralSecurityException e) + { + throw new KeyManagementException(e); + } + } + + return findX509KeyManager(kms); + } + + protected X509TrustManager selectTrustManager(TrustManager[] tms) throws KeyManagementException + { + if (tms == null) + { + try + { + /* + * "[...] the installed security providers will be searched for the highest priority + * implementation of the appropriate factory." + */ + + // TODO[jsse] Is PKIX a reasonable algorithm to use here? + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + // TODO[jsse] Is this supported generally? + tmf.init((KeyStore)null); + tms = tmf.getTrustManagers(); + } + catch (GeneralSecurityException e) + { + throw new KeyManagementException(e); + } + } + + return findX509TrustManager(tms); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLEngine.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLEngine.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLEngine.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLEngine.java 2016-12-09 02:38:07.000000000 +0000 @@ -0,0 +1,425 @@ +package org.bouncycastle.jsse.provider; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLEngineResult.Status; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSession; +import javax.net.ssl.X509TrustManager; + +import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsProtocol; +import org.bouncycastle.tls.TlsServerProtocol; + +/* + * TODO[jsse] Currently doesn't properly support NIO usage, or conform very well with SSLEngine javadoc + * - e.g. "The wrap() and unwrap() methods may execute concurrently of each other." is not true yet. + */ +class ProvSSLEngine + extends SSLEngine + implements ProvTlsManager +{ + protected final ProvSSLContextSpi context; + protected final ContextData contextData; + + protected ProvSSLParameters sslParameters; + protected boolean enableSessionCreation = false; + protected boolean useClientMode = true; + + protected boolean initialHandshakeBegun = false; + protected HandshakeStatus handshakeStatus = HandshakeStatus.NOT_HANDSHAKING; + protected TlsProtocol protocol = null; + protected ProvTlsPeer protocolPeer = null; + protected SSLSession session = ProvSSLSession.NULL_SESSION; + protected SSLSession handshakeSession = null; + + protected ProvSSLEngine(ProvSSLContextSpi context, ContextData contextData) + { + super(); + + this.context = context; + this.contextData = contextData; + this.sslParameters = ProvSSLParameters.extractDefaultParameters(context); + } + + protected ProvSSLEngine(ProvSSLContextSpi context, ContextData contextData, String host, int port) + { + super(host, port); + + this.context = context; + this.contextData = contextData; + this.sslParameters = ProvSSLParameters.extractDefaultParameters(context);; + } + + public ProvSSLContextSpi getContext() + { + return context; + } + + public ContextData getContextData() + { + return contextData; + } + + @Override + public synchronized void beginHandshake() + throws SSLException + { + if (initialHandshakeBegun) + { + throw new UnsupportedOperationException("Renegotiation not supported"); + } + + this.initialHandshakeBegun = true; + + // TODO[jsse] Check for session to re-use and apply to handshake + // TODO[jsse] Allocate this.handshakeSession and update it during handshake + + try + { + if (this.useClientMode) + { + TlsClientProtocol clientProtocol = new TlsClientProtocol(); + this.protocol = clientProtocol; + + ProvTlsClient client = new ProvTlsClient(this); + this.protocolPeer = client; + + clientProtocol.connect(client); + } + else + { + TlsServerProtocol serverProtocol = new TlsServerProtocol(); + this.protocol = serverProtocol; + + ProvTlsServer server = new ProvTlsServer(this); + this.protocolPeer = server; + + serverProtocol.accept(server); + } + } + catch (IOException e) + { + throw new SSLException(e); + } + + determineHandshakeStatus(); + } + + @Override + public synchronized void closeInbound() + throws SSLException + { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized void closeOutbound() + { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized Runnable getDelegatedTask() + { + return null; + } + + @Override + public synchronized String[] getEnabledCipherSuites() + { + return sslParameters.getCipherSuites(); + } + + @Override + public synchronized String[] getEnabledProtocols() + { + return sslParameters.getProtocols(); + } + + @Override + public synchronized boolean getEnableSessionCreation() + { + return enableSessionCreation; + } + + @Override + public synchronized SSLSession getHandshakeSession() + { + // TODO[jsse] this.handshakeSession needs to be reset (to null) whenever not handshaking + + return handshakeSession; + } + + @Override + public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() + { + return handshakeStatus; + } + + @Override + public synchronized boolean getNeedClientAuth() + { + return sslParameters.getNeedClientAuth(); + } + + @Override + public synchronized SSLSession getSession() + { + // TODO[jsse] this.session needs to be set after a successful handshake + + return session; + } + + @Override + public synchronized SSLParameters getSSLParameters() + { + return SSLParametersUtil.toSSLParameters(sslParameters); + } + + public synchronized ProvSSLParameters getProvSSLParameters() + { + return sslParameters; + } + + @Override + public synchronized String[] getSupportedCipherSuites() + { + return context.getSupportedCipherSuites(); + } + + @Override + public synchronized String[] getSupportedProtocols() + { + return context.getSupportedProtocols(); + } + + @Override + public synchronized boolean getUseClientMode() + { + return useClientMode; + } + + @Override + public synchronized boolean getWantClientAuth() + { + return sslParameters.getWantClientAuth(); + } + + @Override + public synchronized boolean isInboundDone() + { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized boolean isOutboundDone() + { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized void setEnabledCipherSuites(String[] suites) + { + if (!context.isSupportedCipherSuites(suites)) + { + throw new IllegalArgumentException("'suites' cannot be null, or contain unsupported cipher suites"); + } + + sslParameters.setCipherSuites(suites); + } + + @Override + public synchronized void setEnabledProtocols(String[] protocols) + { + if (!context.isSupportedProtocols(protocols)) + { + throw new IllegalArgumentException("'protocols' cannot be null, or contain unsupported protocols"); + } + + sslParameters.setProtocols(protocols); + } + + @Override + public synchronized void setEnableSessionCreation(boolean flag) + { + this.enableSessionCreation = flag; + } + + @Override + public synchronized void setNeedClientAuth(boolean need) + { + sslParameters.setNeedClientAuth(need); + } + + @Override + public synchronized void setSSLParameters(SSLParameters sslParameters) + { + this.sslParameters = SSLParametersUtil.toProvSSLParameters(sslParameters); + } + + @Override + public synchronized void setUseClientMode(boolean mode) + { + if (initialHandshakeBegun && mode != this.useClientMode) + { + throw new IllegalArgumentException("Mode cannot be changed after the initial handshake has begun"); + } + + this.useClientMode = mode; + } + + @Override + public synchronized void setWantClientAuth(boolean want) + { + sslParameters.setWantClientAuth(want); + } + + @Override + public synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts, int offset, int length) + throws SSLException + { + // TODO[jsse] Argument checks - see javadoc + + if (!initialHandshakeBegun) + { + beginHandshake(); + } + + HandshakeStatus prevHandshakeStatus = handshakeStatus; + int bytesConsumed = 0, bytesProduced = 0; + + if (!protocol.isClosed()) + { + byte[] buf = new byte[src.remaining()]; + src.get(buf); + + try + { + protocol.offerInput(buf); + } + catch (IOException e) + { + // TODO[jsse] Throw a subclass of SSLException? + throw new SSLException(e); + } + + bytesConsumed += buf.length; + } + + int appDataAvailable = protocol.getAvailableInputBytes(); + for (int dstIndex = 0; dstIndex < length && appDataAvailable > 0; ++dstIndex) + { + ByteBuffer dst = dsts[dstIndex]; + int count = Math.min(dst.remaining(), appDataAvailable); + + byte[] input = new byte[count]; + int numRead = protocol.readInput(input, 0, count); + assert numRead == count; + + dst.put(input); + + bytesProduced += count; + appDataAvailable -= count; + } + + Status returnStatus = Status.OK; + if (appDataAvailable > 0) + { + returnStatus = Status.BUFFER_OVERFLOW; + } + else if (protocol.isClosed()) + { + returnStatus = Status.CLOSED; + } + + determineHandshakeStatus(); + + HandshakeStatus returnHandshakeStatus = handshakeStatus; + if (handshakeStatus == HandshakeStatus.NOT_HANDSHAKING && prevHandshakeStatus != HandshakeStatus.NOT_HANDSHAKING) + { + returnHandshakeStatus = HandshakeStatus.FINISHED; + } + + return new SSLEngineResult(returnStatus, returnHandshakeStatus, bytesConsumed, bytesProduced); + } + + @Override + public synchronized SSLEngineResult wrap(ByteBuffer[] srcs, int offset, int length, ByteBuffer dst) + throws SSLException + { + throw new UnsupportedOperationException(); + } + + protected void determineHandshakeStatus() + { + // NOTE: We currently never delegate tasks (will never have status HandshakeStatus.NEED_TASK) + + if (!initialHandshakeBegun || protocolPeer.isHandshakeComplete()) + { + handshakeStatus = HandshakeStatus.NOT_HANDSHAKING; + } + else if (protocol.getAvailableOutputBytes() > 0) + { + handshakeStatus = HandshakeStatus.NEED_WRAP; + } + else if (protocol.isClosed()) + { + handshakeStatus = HandshakeStatus.NOT_HANDSHAKING; + } + else + { + handshakeStatus = HandshakeStatus.NEED_UNWRAP; + } + } + + public boolean isClientTrusted(X509Certificate[] chain, String authType) + { + // TODO[jsse] Consider X509ExtendedTrustManager and/or HostnameVerifier functionality + + X509TrustManager tm = contextData.getTrustManager(); + if (tm != null) + { + try + { + tm.checkClientTrusted(chain, authType); + return true; + } + catch (CertificateException e) + { + } + } + return false; + } + + public boolean isServerTrusted(X509Certificate[] chain, String authType) + { + // TODO[jsse] Consider X509ExtendedTrustManager and/or HostnameVerifier functionality + + X509TrustManager tm = contextData.getTrustManager(); + if (tm != null) + { + try + { + tm.checkServerTrusted(chain, authType); + return true; + } + catch (CertificateException e) + { + } + } + return false; + } + + public synchronized void notifyHandshakeComplete(SSLSession session) + { + this.session = session; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLParameters.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLParameters.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLParameters.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLParameters.java 2016-12-09 02:31:59.000000000 +0000 @@ -0,0 +1,94 @@ +package org.bouncycastle.jsse.provider; + +class ProvSSLParameters +{ + static final boolean hasSslParameters; + + static + { + Class clazz = null; + try + { + clazz = ProvSSLServerSocket.class.getClassLoader().loadClass("javax.net.ssl.SSLParameters"); + } + catch (Exception e) + { + clazz = null; + } + + hasSslParameters = (clazz != null); + } + + private String[] cipherSuites; + private String[] protocols; + private boolean needClientAuth; + private boolean wantClientAuth; + + public void setCipherSuites(String[] cipherSuites) + { + this.cipherSuites = cipherSuites; + } + + public void setProtocols(String[] protocols) + { + this.protocols = protocols; + } + + public void setNeedClientAuth(boolean needClientAuth) + { + this.needClientAuth = needClientAuth; + } + + public void setWantClientAuth(boolean wantClientAuth) + { + this.wantClientAuth = wantClientAuth; + } + + public String[] getCipherSuites() + { + return cipherSuites.clone(); + } + + public String[] getProtocols() + { + return protocols.clone(); + } + + public boolean getNeedClientAuth() + { + return needClientAuth; + } + + public boolean getWantClientAuth() + { + return wantClientAuth; + } + + static ProvSSLParameters extractDefaultParameters(ProvSSLContextSpi context) + { + if (hasSslParameters) + { + return SSLParametersUtil.toProvSSLParameters(context.engineGetDefaultSSLParameters()); + } + else + { + ProvSSLParameters params = new ProvSSLParameters(); + + String[] cipherSuites = context.getDefaultCipherSuites(); + if (cipherSuites != null) + { + params.setCipherSuites(cipherSuites); + } + String[] protocols = context.getDefaultProtocols(); + if (protocols != null) + { + params.setProtocols(protocols); + } + + params.setNeedClientAuth(false); + params.setWantClientAuth(false); + + return params; + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLServerSocketFactory.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLServerSocketFactory.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLServerSocketFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLServerSocketFactory.java 2016-11-01 20:33:01.000000000 +0000 @@ -0,0 +1,56 @@ +package org.bouncycastle.jsse.provider; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; + +import javax.net.ssl.SSLServerSocketFactory; + +class ProvSSLServerSocketFactory + extends SSLServerSocketFactory +{ + protected final ProvSSLContextSpi context; + + ProvSSLServerSocketFactory(ProvSSLContextSpi context) + { + super(); + + this.context = context; + } + + @Override + public ServerSocket createServerSocket() throws IOException + { + return new ProvSSLServerSocket(context, context.createContextData()); + } + + @Override + public ServerSocket createServerSocket(int port) throws IOException + { + return new ProvSSLServerSocket(context, context.createContextData(), port); + } + + @Override + public ServerSocket createServerSocket(int port, int backlog) throws IOException + { + return new ProvSSLServerSocket(context, context.createContextData(), port, backlog); + } + + @Override + public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) throws IOException + { + return new ProvSSLServerSocket(context, context.createContextData(), port, backlog, ifAddress); + } + + @Override + public String[] getDefaultCipherSuites() + { + return context.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() + { + return context.getSupportedCipherSuites(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLServerSocket.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLServerSocket.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLServerSocket.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLServerSocket.java 2016-12-09 02:31:59.000000000 +0000 @@ -0,0 +1,221 @@ +package org.bouncycastle.jsse.provider; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.nio.channels.ServerSocketChannel; + +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLSocket; + +class ProvSSLServerSocket + extends SSLServerSocket +{ + + protected final ProvSSLContextSpi context; + protected final ContextData contextData; + + protected ProvSSLParameters sslParameters; + protected boolean enableSessionCreation = false; + protected boolean useClientMode = false; + + protected ProvSSLServerSocket(ProvSSLContextSpi context, ContextData contextData) + throws IOException + { + super(); + + this.context = context; + this.contextData = contextData; + this.sslParameters = ProvSSLParameters.extractDefaultParameters(context); + } + + protected ProvSSLServerSocket(ProvSSLContextSpi context, ContextData contextData, int port) + throws IOException + { + super(port); + + this.context = context; + this.contextData = contextData; + this.sslParameters = ProvSSLParameters.extractDefaultParameters(context); + } + + protected ProvSSLServerSocket(ProvSSLContextSpi context, ContextData contextData, int port, int backlog) + throws IOException + { + super(port, backlog); + + this.context = context; + this.contextData = contextData; + this.sslParameters = ProvSSLParameters.extractDefaultParameters(context); + } + + protected ProvSSLServerSocket(ProvSSLContextSpi context, ContextData contextData, int port, int backlog, InetAddress address) + throws IOException + { + super(port, backlog, address); + + this.context = context; + this.contextData = contextData; + this.sslParameters = ProvSSLParameters.extractDefaultParameters(context); + } + + @Override + public synchronized Socket accept() throws IOException + { +// SSLEngine engine = context.engineCreateSSLEngine(getInetAddress().getHostName(), getLocalPort()); +// SSLSocket socket = new ProvSSLSocket(engine); + SSLSocket socket = new ProvSSLSocketDirect(context, contextData); + + implAccept(socket); + + if (ProvSSLParameters.hasSslParameters) + { + socket.setSSLParameters(SSLParametersUtil.toSSLParameters(sslParameters)); + } + else + { + String[] cipherSuites = sslParameters.getCipherSuites(); + if (cipherSuites != null) + { + socket.setEnabledCipherSuites(cipherSuites); + } + String[] protocols = sslParameters.getProtocols(); + if (protocols != null) + { + socket.setEnabledProtocols(protocols); + } + + if (sslParameters.getNeedClientAuth()) + { + socket.setNeedClientAuth(true); + } + else if (sslParameters.getWantClientAuth()) + { + socket.setWantClientAuth(true); + } + else + { + socket.setWantClientAuth(false); + } + } + + socket.setEnableSessionCreation(enableSessionCreation); + socket.setUseClientMode(useClientMode); + + return socket; + } + + @Override + public ServerSocketChannel getChannel() + { +// return super.getChannel(); + throw new UnsupportedOperationException(); + } + + @Override + public synchronized boolean getEnableSessionCreation() + { + return enableSessionCreation; + } + + @Override + public synchronized String[] getEnabledCipherSuites() + { + return sslParameters.getCipherSuites(); + } + + @Override + public synchronized String[] getEnabledProtocols() + { + return sslParameters.getProtocols(); + } + + @Override + public synchronized boolean getNeedClientAuth() + { + return sslParameters.getNeedClientAuth(); + } + + @Override + public synchronized SSLParameters getSSLParameters() + { + return SSLParametersUtil.toSSLParameters(sslParameters); + } + + @Override + public synchronized String[] getSupportedCipherSuites() + { + return context.getSupportedCipherSuites(); + } + + @Override + public synchronized String[] getSupportedProtocols() + { + return context.getSupportedProtocols(); + } + + @Override + public synchronized boolean getUseClientMode() + { + return useClientMode; + } + + @Override + public synchronized boolean getWantClientAuth() + { + return sslParameters.getWantClientAuth(); + } + + @Override + public synchronized void setEnableSessionCreation(boolean flag) + { + this.enableSessionCreation = flag; + } + + @Override + public synchronized void setEnabledCipherSuites(String[] suites) + { + if (!context.isSupportedCipherSuites(suites)) + { + throw new IllegalArgumentException("'suites' cannot be null, or contain unsupported cipher suites"); + } + + sslParameters.setCipherSuites(suites); + } + + @Override + public synchronized void setEnabledProtocols(String[] protocols) + { + if (!context.isSupportedProtocols(protocols)) + { + throw new IllegalArgumentException("'protocols' cannot be null, or contain unsupported protocols"); + } + + sslParameters.setProtocols(protocols); + } + + @Override + public synchronized void setNeedClientAuth(boolean need) + { + sslParameters.setNeedClientAuth(need); + } + + @Override + public synchronized void setSSLParameters(SSLParameters sslParameters) + { + this.sslParameters = SSLParametersUtil.toProvSSLParameters(sslParameters); + } + + @Override + public synchronized void setUseClientMode(boolean mode) + { + this.useClientMode = mode; + } + + @Override + public synchronized void setWantClientAuth(boolean want) + { + sslParameters.setWantClientAuth(want); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionContext.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionContext.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionContext.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionContext.java 2016-12-09 03:24:49.000000000 +0000 @@ -0,0 +1,131 @@ +package org.bouncycastle.jsse.provider; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; + +import org.bouncycastle.tls.SessionID; +import org.bouncycastle.tls.TlsSession; + +/* + * TODO[jsse] + * - Need to add sessions to the context at handshake completion + * - Implement the cache/timeout mechanisms + */ +class ProvSSLSessionContext + implements SSLSessionContext +{ + static final boolean hasExtendedSSLSession; + + static + { + Class clazz = null; + try + { + clazz = ProvSSLServerSocket.class.getClassLoader().loadClass("javax.net.ssl.ExtendedSSLSession"); + } + catch (Exception e) + { + clazz = null; + } + + hasExtendedSSLSession = (clazz != null); + } + + protected final Map sessionMap = Collections.synchronizedMap(new HashMap()); + + protected final ProvSSLContextSpi sslContext; + protected int sessionCacheSize = 0; + protected int sessionTimeout = 0; + + ProvSSLSessionContext(ProvSSLContextSpi sslContext) + { + this.sslContext = sslContext; + } + + ProvSSLContextSpi getSSLContext() + { + return sslContext; + } + + SSLSession reportSession(TlsSession tlsSession) + { + // TODO[jsse] Check for existing session with same ID + + ProvSSLSession sslSession = new ProvSSLSession(this, tlsSession); + + // TODO[jsse] Register session for re-use + + if (hasExtendedSSLSession) + { + return new ProvExtendedSSLSession(sslSession); + } + + return sslSession; + } + + public Enumeration getIds() + { + synchronized (sessionMap) + { + Collection keys = sessionMap.keySet(); + ArrayList ids = new ArrayList(keys.size()); + for (SessionID key : keys) + { + // TODO[jsse] Filter out invalidated/timed-out sessions? + ids.add(key.getBytes()); + } + return Collections.enumeration(ids); + } + } + + public SSLSession getSession(byte[] sessionId) + { + SessionID key = new SessionID(sessionId); + ProvSSLSession session = sessionMap.get(key); + + // TODO[jsse] Should we return a session if it's been invalidated/timed-out? + + return session; + } + + public synchronized int getSessionCacheSize() + { + return sessionCacheSize; + } + + public synchronized int getSessionTimeout() + { + return sessionTimeout; + } + + public synchronized void setSessionCacheSize(int size) throws IllegalArgumentException + { + if (size < 0) + { + throw new IllegalArgumentException("'size' cannot be < 0"); + } + + this.sessionCacheSize = size; + + // TODO[jsse] Immediately discard any extra sessions + } + + public synchronized void setSessionTimeout(int seconds) throws IllegalArgumentException + { + if (seconds < 0) + { + throw new IllegalArgumentException("'seconds' cannot be < 0"); + } + + this.sessionTimeout = seconds; + + // TODO[jsse] Immediately check the new timeout for all sessions + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSession.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSession.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSession.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSession.java 2016-12-09 03:32:31.000000000 +0000 @@ -0,0 +1,211 @@ +package org.bouncycastle.jsse.provider; + +import java.security.Principal; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionBindingEvent; +import javax.net.ssl.SSLSessionBindingListener; +import javax.net.ssl.SSLSessionContext; +import javax.security.auth.x500.X500Principal; + +import org.bouncycastle.tls.SessionParameters; +import org.bouncycastle.tls.TlsSession; +import org.bouncycastle.util.Arrays; + +// TODO[jsse] Serializable ? +class ProvSSLSession + implements SSLSession +{ + // TODO[jsse] Ensure this behaves according to the javadoc for SSLSocket.getSession and SSLEngine.getSession + protected final static ProvSSLSession NULL_SESSION = new ProvSSLSession(null, null); + + protected final Map valueMap = Collections.synchronizedMap(new HashMap()); + + protected final ProvSSLSessionContext sslSessionContext; + protected final TlsSession tlsSession; + protected final SessionParameters sessionParameters; + + ProvSSLSession(ProvSSLSessionContext sslSessionContext, TlsSession tlsSession) + { + this.sslSessionContext = sslSessionContext; + this.tlsSession = tlsSession; + this.sessionParameters = tlsSession == null ? null : tlsSession.exportSessionParameters(); + } + + public int getApplicationBufferSize() + { + throw new UnsupportedOperationException(); + } + + public String getCipherSuite() + { + return sessionParameters == null + ? null + : sslSessionContext.getSSLContext().getCipherSuiteString(sessionParameters.getCipherSuite()); + } + + public long getCreationTime() + { + throw new UnsupportedOperationException(); + } + + public byte[] getId() + { + return tlsSession == null + ? null + : Arrays.clone(tlsSession.getSessionID()); + } + + public long getLastAccessedTime() + { + throw new UnsupportedOperationException(); + } + + public Certificate[] getLocalCertificates() + { + if (sessionParameters != null) + { + X509Certificate[] chain = JsseUtils.getX509CertificateChain(sessionParameters.getLocalCertificate()); + if (chain != null && chain.length > 0) + { + return chain; + } + } + + return null; + } + + public Principal getLocalPrincipal() + { + return sessionParameters == null + ? null + : JsseUtils.getSubject(sessionParameters.getLocalCertificate()); + } + + public int getPacketBufferSize() + { + throw new UnsupportedOperationException(); + } + + public javax.security.cert.X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException + { + /* + * TODO[jsse] "Note: this method exists for compatibility with previous releases. New + * applications should use getPeerCertificates() instead." + */ + throw new UnsupportedOperationException(); + } + + public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException + { + if (sessionParameters != null) + { + X509Certificate[] chain = JsseUtils.getX509CertificateChain(sessionParameters.getPeerCertificate()); + if (chain != null && chain.length > 0) + { + return chain; + } + } + + throw new SSLPeerUnverifiedException("No peer identity established"); + } + + public String getPeerHost() + { + // TODO[jsse] "It is mainly used as a hint for SSLSession caching strategies." + return null; + } + + public int getPeerPort() + { + // TODO[jsse] "It is mainly used as a hint for SSLSession caching strategies." + return -1; + } + + public Principal getPeerPrincipal() throws SSLPeerUnverifiedException + { + if (sessionParameters != null) + { + X500Principal principal = JsseUtils.getSubject(sessionParameters.getPeerCertificate()); + if (principal != null) + { + return principal; + } + } + + throw new SSLPeerUnverifiedException("No peer identity established"); + } + + public String getProtocol() + { + return sessionParameters == null + ? null + : sslSessionContext.getSSLContext().getProtocolString(sessionParameters.getNegotiatedVersion()); + } + + public SSLSessionContext getSessionContext() + { + return sslSessionContext; + } + + public Object getValue(String name) + { + return valueMap.get(name); + } + + public String[] getValueNames() + { + synchronized (valueMap) + { + return valueMap.keySet().toArray(new String[valueMap.size()]); + } + } + + public void invalidate() + { + if (tlsSession != null) + { + tlsSession.invalidate(); + } + } + + public boolean isValid() + { + return tlsSession != null && tlsSession.isResumable(); + } + + public void putValue(String name, Object value) + { + notifyUnbound(name, valueMap.put(name, value)); + notifyBound(name, value); + } + + public void removeValue(String name) + { + notifyUnbound(name, valueMap.remove(name)); + } + + protected void notifyBound(String name, Object value) + { + if (value instanceof SSLSessionBindingListener) + { + new SessionBindingListenerAdapter((SSLSessionBindingListener)value) + .valueBound(new SSLSessionBindingEvent(this, name)); + } + } + + protected void notifyUnbound(String name, Object value) + { + if (value instanceof SSLSessionBindingListener) + { + new SessionBindingListenerAdapter((SSLSessionBindingListener)value) + .valueUnbound(new SSLSessionBindingEvent(this, name)); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketBase.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketBase.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketBase.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketBase.java 2016-10-15 20:29:16.000000000 +0000 @@ -0,0 +1,99 @@ +package org.bouncycastle.jsse.provider; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.nio.channels.SocketChannel; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSocket; + +abstract class ProvSSLSocketBase + extends SSLSocket +{ + protected final Set listeners = Collections.synchronizedSet( + new HashSet()); + + protected ProvSSLSocketBase() + { + super(); + } + + protected ProvSSLSocketBase(InetAddress address, int port, InetAddress clientAddress, int clientPort) + throws IOException + { + super(address, port, clientAddress, clientPort); + } + + protected ProvSSLSocketBase(InetAddress address, int port) throws IOException + { + super(address, port); + } + + protected ProvSSLSocketBase(String host, int port, InetAddress clientAddress, int clientPort) + throws IOException, UnknownHostException + { + super(host, port, clientAddress, clientPort); + } + + protected ProvSSLSocketBase(String host, int port) throws IOException, UnknownHostException + { + super(host, port); + } + + @Override + public void addHandshakeCompletedListener(HandshakeCompletedListener listener) + { + if (listener == null) + { + throw new IllegalArgumentException("'listener' cannot be null"); + } + + listeners.add(new HandshakeCompletedListenerAdapter(listener)); + } + + @Override + public SocketChannel getChannel() + { +// return super.getChannel(); + throw new UnsupportedOperationException(); + } + + @Override + public boolean getOOBInline() throws SocketException + { + return false; + } + + @Override + public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) + { + if (listener == null) + { + throw new IllegalArgumentException("'listener' cannot be null"); + } + if (!listeners.remove(new HandshakeCompletedListenerAdapter(listener))) + { + throw new IllegalArgumentException("'listener' is not registered"); + } + } + + @Override + public void sendUrgentData(int data) throws IOException + { + throw new UnsupportedOperationException("Urgent data not supported in TLS"); + } + + @Override + public void setOOBInline(boolean on) throws SocketException + { + if (on) + { + throw new UnsupportedOperationException("Urgent data not supported in TLS"); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java 2016-12-09 02:37:27.000000000 +0000 @@ -0,0 +1,433 @@ +package org.bouncycastle.jsse.provider; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSession; +import javax.net.ssl.X509TrustManager; + +import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsProtocol; +import org.bouncycastle.tls.TlsServerProtocol; + +class ProvSSLSocketDirect + extends ProvSSLSocketBase + implements ProvTlsManager +{ + protected final AppDataInput appDataIn = new AppDataInput(); + protected final AppDataOutput appDataOut = new AppDataOutput(); + + protected final ProvSSLContextSpi context; + protected final ContextData contextData; + + protected ProvSSLParameters sslParameters; + protected boolean enableSessionCreation = false; + protected boolean useClientMode = true; + + protected boolean initialHandshakeBegun = false; + protected TlsProtocol protocol = null; + protected ProvTlsPeer protocolPeer = null; + protected SSLSession session = ProvSSLSession.NULL_SESSION; + protected SSLSession handshakeSession = null; + + protected ProvSSLSocketDirect(ProvSSLContextSpi context, ContextData contextData) + { + super(); + + this.context = context; + this.contextData = contextData; + this.sslParameters = ProvSSLParameters.extractDefaultParameters(context); + } + + protected ProvSSLSocketDirect(ProvSSLContextSpi context, ContextData contextData, InetAddress address, int port, InetAddress clientAddress, int clientPort) + throws IOException + { + super(address, port, clientAddress, clientPort); + + this.context = context; + this.contextData = contextData; + this.sslParameters = ProvSSLParameters.extractDefaultParameters(context); + } + + protected ProvSSLSocketDirect(ProvSSLContextSpi context, ContextData contextData, InetAddress address, int port) throws IOException + { + super(address, port); + + this.context = context; + this.contextData = contextData; + this.sslParameters = ProvSSLParameters.extractDefaultParameters(context); + } + + protected ProvSSLSocketDirect(ProvSSLContextSpi context, ContextData contextData, String host, int port, InetAddress clientAddress, int clientPort) + throws IOException, UnknownHostException + { + super(host, port, clientAddress, clientPort); + + this.context = context; + this.contextData = contextData; + this.sslParameters = ProvSSLParameters.extractDefaultParameters(context); + } + + protected ProvSSLSocketDirect(ProvSSLContextSpi context, ContextData contextData, String host, int port) throws IOException, UnknownHostException + { + super(host, port); + + this.context = context; + this.contextData = contextData; + this.sslParameters = ProvSSLParameters.extractDefaultParameters(context); + } + + public ProvSSLContextSpi getContext() + { + return context; + } + + public ContextData getContextData() + { + return contextData; + } + + @Override + public synchronized void close() throws IOException + { + if (protocol != null) + { + protocol.close(); + } + super.close(); + } + + @Override + public synchronized String[] getEnabledCipherSuites() + { + return sslParameters.getCipherSuites(); + } + + @Override + public synchronized String[] getEnabledProtocols() + { + return sslParameters.getProtocols(); + } + + @Override + public synchronized boolean getEnableSessionCreation() + { + return enableSessionCreation; + } + + @Override + public synchronized SSLSession getHandshakeSession() + { + return handshakeSession; + } + + @Override + public InputStream getInputStream() throws IOException + { + return appDataIn; + } + + @Override + public synchronized boolean getNeedClientAuth() + { + return sslParameters.getNeedClientAuth(); + } + + @Override + public OutputStream getOutputStream() throws IOException + { + return appDataOut; + } + + @Override + public synchronized SSLSession getSession() + { + /* + * "This method will initiate the initial handshake if necessary and then block until the + * handshake has been established." + */ + try + { + handshakeIfNecessary(); + } + catch (Exception e) + { + // TODO[jsse] Logging? + } + + return session; + } + + @Override + public synchronized SSLParameters getSSLParameters() + { + return SSLParametersUtil.toSSLParameters(sslParameters); + } + + public synchronized ProvSSLParameters getProvSSLParameters() + { + return sslParameters; + } + + @Override + public synchronized String[] getSupportedCipherSuites() + { + return context.getSupportedCipherSuites(); + } + + @Override + public synchronized String[] getSupportedProtocols() + { + return context.getSupportedProtocols(); + } + + @Override + public synchronized boolean getUseClientMode() + { + return useClientMode; + } + + @Override + public synchronized boolean getWantClientAuth() + { + return sslParameters.getWantClientAuth(); + } + + @Override + public synchronized void setEnabledCipherSuites(String[] suites) + { + if (!context.isSupportedCipherSuites(suites)) + { + throw new IllegalArgumentException("'suites' cannot be null, or contain unsupported cipher suites"); + } + + sslParameters.setCipherSuites(suites); + } + + @Override + public synchronized void setEnabledProtocols(String[] protocols) + { + if (!context.isSupportedProtocols(protocols)) + { + throw new IllegalArgumentException("'protocols' cannot be null, or contain unsupported protocols"); + } + + sslParameters.setProtocols(protocols); + } + + @Override + public synchronized void setEnableSessionCreation(boolean flag) + { + this.enableSessionCreation = flag; + } + + @Override + public synchronized void setNeedClientAuth(boolean need) + { + sslParameters.setNeedClientAuth(need); + } + + @Override + public synchronized void setSSLParameters(SSLParameters sslParameters) + { + this.sslParameters = SSLParametersUtil.toProvSSLParameters(sslParameters); + } + + @Override + public synchronized void setUseClientMode(boolean mode) + { + if (initialHandshakeBegun && mode != this.useClientMode) + { + throw new IllegalArgumentException("Mode cannot be changed after the initial handshake has begun"); + } + + this.useClientMode = mode; + } + + @Override + public synchronized void setWantClientAuth(boolean want) + { + sslParameters.setWantClientAuth(want); + } + + @Override + public synchronized void startHandshake() throws IOException + { + if (initialHandshakeBegun) + { + throw new UnsupportedOperationException("Renegotiation not supported"); + } + + this.initialHandshakeBegun = true; + + try + { + // TODO[jsse] Check for session to re-use and apply to handshake + // TODO[jsse] Allocate this.handshakeSession and update it during handshake + + if (this.useClientMode) + { + TlsClientProtocol clientProtocol = new TlsClientProtocol(super.getInputStream(), super.getOutputStream()); + this.protocol = clientProtocol; + + ProvTlsClient client = new ProvTlsClient(this); + this.protocolPeer = client; + + clientProtocol.connect(client); + } + else + { + TlsServerProtocol serverProtocol = new TlsServerProtocol(super.getInputStream(), super.getOutputStream()); + this.protocol = serverProtocol; + + ProvTlsServer server = new ProvTlsServer(this); + this.protocolPeer = server; + + serverProtocol.accept(server); + } + } + finally + { + this.handshakeSession = null; + } + } + + public boolean isClientTrusted(X509Certificate[] chain, String authType) + { + // TODO[jsse] Consider X509ExtendedTrustManager and/or HostnameVerifier functionality + + X509TrustManager tm = contextData.getTrustManager(); + if (tm != null) + { + try + { + tm.checkClientTrusted(chain, authType); + return true; + } + catch (CertificateException e) + { + } + } + return false; + } + + public boolean isServerTrusted(X509Certificate[] chain, String authType) + { + // TODO[jsse] Consider X509ExtendedTrustManager and/or HostnameVerifier functionality + + X509TrustManager tm = contextData.getTrustManager(); + if (tm != null) + { + try + { + tm.checkServerTrusted(chain, authType); + return true; + } + catch (CertificateException e) + { + } + } + return false; + } + + public synchronized void notifyHandshakeComplete(SSLSession session) + { + this.session = session; + } + + synchronized void handshakeIfNecessary() throws IOException + { + if (!initialHandshakeBegun) + { + startHandshake(); + } + } + + class AppDataInput extends InputStream + { + @Override + public int available() throws IOException + { + synchronized (ProvSSLSocketDirect.this) + { + return protocol == null + ? 0 + : protocol.applicationDataAvailable(); + } + } + + @Override + public void close() throws IOException + { + ProvSSLSocketDirect.this.close(); + } + + @Override + public int read() throws IOException + { + handshakeIfNecessary(); + + byte[] buf = new byte[1]; + int ret = protocol.readApplicationData(buf, 0, 1); + return ret < 0 ? -1 : buf[0] & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException + { + if (len < 1) + { + return 0; + } + + handshakeIfNecessary(); + return protocol.readApplicationData(b, off, len); + } + } + + class AppDataOutput extends OutputStream + { + @Override + public void close() throws IOException + { + ProvSSLSocketDirect.this.close(); + } + + @Override + public void flush() throws IOException + { + synchronized (ProvSSLSocketDirect.this) + { + if (protocol != null) + { + protocol.flush(); + } + } + } + + @Override + public void write(int b) throws IOException + { + handshakeIfNecessary(); + + byte[] buf = new byte[]{ (byte)b }; + protocol.writeApplicationData(buf, 0, 1); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException + { + if (len > 0) + { + handshakeIfNecessary(); + protocol.writeApplicationData(b, off, len); + } + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketFactory.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketFactory.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketFactory.java 2016-11-01 20:33:01.000000000 +0000 @@ -0,0 +1,96 @@ +package org.bouncycastle.jsse.provider; + +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLSocketFactory; + +class ProvSSLSocketFactory + extends SSLSocketFactory +{ + protected final ProvSSLContextSpi context; + + ProvSSLSocketFactory(ProvSSLContextSpi context) + { + super(); + + this.context = context; + } + + @Override + public Socket createSocket() throws IOException + { +// SSLEngine engine = context.engineCreateSSLEngine(); +// return new ProvSSLSocket(engine); + return new ProvSSLSocketDirect(context, context.createContextData()); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException + { +// SSLEngine engine = context.engineCreateSSLEngine(host.getHostName(), port); +// return new ProvSSLSocket(engine, host, port); + return new ProvSSLSocketDirect(context, context.createContextData(), host, port); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) + throws IOException + { +// SSLEngine engine = context.engineCreateSSLEngine(address.getHostName(), port); +// return new ProvSSLSocket(engine, address, port, localAddress, localPort); + return new ProvSSLSocketDirect(context, context.createContextData(), address, port, localAddress, localPort); + } + + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException + { +// SSLEngine engine = context.engineCreateSSLEngine(host, port); +// return new ProvSSLSocket(engine, host, port); + return new ProvSSLSocketDirect(context, context.createContextData(), host, port); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) + throws IOException, UnknownHostException + { +// SSLEngine engine = context.engineCreateSSLEngine(host, port); +// return new ProvSSLSocket(engine, host, port, localHost, localPort); + return new ProvSSLSocketDirect(context, context.createContextData(), host, port, localHost, localPort); + } + + public Socket createSocket(Socket s, InputStream consumed, boolean autoClose) throws IOException + { + /* + * TODO[jsse] "Creates a server mode Socket layered over an existing connected socket, + * and is able to read data which has already been consumed/removed from the Socket's + * underlying InputStream." + */ + throw new UnsupportedOperationException(); + } + + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException + { + /* + * TODO[jsse] + * "Returns a socket layered over an existing socket connected to the named host, at the given port." + */ + throw new UnsupportedOperationException(); + } + + @Override + public String[] getDefaultCipherSuites() + { + return context.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() + { + return context.getSupportedCipherSuites(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocket.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocket.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocket.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocket.java 2016-11-06 20:28:00.000000000 +0000 @@ -0,0 +1,233 @@ +package org.bouncycastle.jsse.provider; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSession; + +class ProvSSLSocket + extends ProvSSLSocketBase +{ + protected final SSLEngine engine; + + protected ProvSSLSocket(SSLEngine engine) + { + super(); + + this.engine = engine; + } + + protected ProvSSLSocket(SSLEngine engine, InetAddress address, int port) throws IOException + { + super(address, port); + + this.engine = engine; + } + + protected ProvSSLSocket(SSLEngine engine, InetAddress address, int port, InetAddress clientAddress, int clientPort) throws IOException + { + super(address, port, clientAddress, clientPort); + + this.engine = engine; + } + + protected ProvSSLSocket(SSLEngine engine, String host, int port) throws IOException, UnknownHostException + { + super(host, port); + + this.engine = engine; + } + + protected ProvSSLSocket(SSLEngine engine, String host, int port, InetAddress clientAddress, int clientPort) + throws IOException, UnknownHostException + { + super(host, port, clientAddress, clientPort); + + this.engine = engine; + } + + @Override + public synchronized void close() throws IOException + { + // TODO[jsse] See javadoc for full discussion of SSLEngine closure + + engine.closeOutbound(); + + // TODO[jsse] + // - Flush output by calling engine.wrap while not CLOSED + // - Check under what circumstances need to call engine.closeInbound + + super.close(); + } + + @Override + public String[] getEnabledCipherSuites() + { + return engine.getEnabledCipherSuites(); + } + + @Override + public String[] getEnabledProtocols() + { + return engine.getEnabledProtocols(); + } + + @Override + public boolean getEnableSessionCreation() + { + return engine.getEnableSessionCreation(); + } + + @Override + public SSLSession getHandshakeSession() + { + return engine.getHandshakeSession(); + } + + @Override + public InputStream getInputStream() throws IOException + { +// return super.getInputStream(); + throw new UnsupportedOperationException(); + } + + @Override + public boolean getNeedClientAuth() + { + return engine.getNeedClientAuth(); + } + + @Override + public OutputStream getOutputStream() throws IOException + { +// return super.getOutputStream(); + throw new UnsupportedOperationException(); + } + + @Override + public SSLSession getSession() + { + return engine.getSession(); + } + + @Override + public SSLParameters getSSLParameters() + { + return engine.getSSLParameters(); + } + + @Override + public String[] getSupportedCipherSuites() + { + return engine.getSupportedCipherSuites(); + } + + @Override + public String[] getSupportedProtocols() + { + return engine.getSupportedProtocols(); + } + + @Override + public boolean getUseClientMode() + { + return engine.getUseClientMode(); + } + + @Override + public boolean getWantClientAuth() + { + return engine.getWantClientAuth(); + } + + @Override + public void setEnabledCipherSuites(String[] suites) + { + engine.setEnabledCipherSuites(suites); + } + + @Override + public void setEnabledProtocols(String[] protocols) + { + engine.setEnabledProtocols(protocols); + } + + @Override + public void setEnableSessionCreation(boolean flag) + { + engine.setEnableSessionCreation(flag); + } + + @Override + public void setNeedClientAuth(boolean need) + { + engine.setNeedClientAuth(need); + } + + @Override + public void setSSLParameters(SSLParameters params) + { + engine.setSSLParameters(params); + } + + @Override + public void setUseClientMode(boolean mode) + { + engine.setUseClientMode(mode); + } + + @Override + public void setWantClientAuth(boolean want) + { + engine.setWantClientAuth(want); + } + + @Override + public void startHandshake() throws IOException + { + /* + * "This method is synchronous for the initial handshake on a connection and returns when the negotiated handshake is complete." + */ + + // TODO[jsse] Consider checking Thread.interrupted occasionally and aborting with InterruptedIOException accordingly. + + // TODO[jsse] +// engine.beginHandshake(); +// +// HandshakeStatus status = engine.getHandshakeStatus(); +// while (status != HandshakeStatus.NOT_HANDSHAKING) +// { +// switch (status) +// { +// case FINISHED: +// break; +// case NEED_TASK: +// break; +// case NEED_UNWRAP: +// break; +// case NEED_WRAP: +// break; +// } +// } + + throw new UnsupportedOperationException(); + + // TODO[jsse] +// if (!listeners.isEmpty()) +// { +// HandshakeCompletedEvent event = new HandshakeCompletedEvent(this, getSession()); +// synchronized (listeners) +// { +// for (HandshakeCompletedListener listener : listeners) +// { +// listener.handshakeCompleted(event); +// } +// } +// } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClient.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClient.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClient.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClient.java 2016-12-09 02:39:57.000000000 +0000 @@ -0,0 +1,264 @@ +package org.bouncycastle.jsse.provider; + +import java.io.IOException; +import java.net.Socket; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.Set; +import java.util.Vector; + +import javax.net.ssl.SSLSession; +import javax.net.ssl.X509KeyManager; +import javax.security.auth.x500.X500Principal; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.CertificateRequest; +import org.bouncycastle.tls.DefaultTlsClient; +import org.bouncycastle.tls.KeyExchangeAlgorithm; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsAuthentication; +import org.bouncycastle.tls.TlsCredentials; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsSession; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.impl.jcajce.JcaDefaultTlsCredentialedSigner; +import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto; +import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedAgreement; + +class ProvTlsClient + extends DefaultTlsClient + implements ProvTlsPeer +{ + protected final ProvTlsManager manager; + protected final ProvSSLParameters sslParameters; + + protected boolean handshakeComplete = false; + + ProvTlsClient(ProvTlsManager manager) + { + super(manager.getContextData().getCrypto()); + + this.manager = manager; + this.sslParameters = manager.getProvSSLParameters(); + } + + public synchronized boolean isHandshakeComplete() + { + return handshakeComplete; + } + + public TlsAuthentication getAuthentication() throws IOException + { + return new TlsAuthentication() + { + public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException + { + // TODO[jsse] What criteria determines whether we are willing to send client authentication? + + int keyExchangeAlgorithm = TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite); + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DH_RSA: + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDH_RSA: + // TODO[jsse] Add support for the static key exchanges + return null; + + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_RSA: + case KeyExchangeAlgorithm.ECDHE_ECDSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + case KeyExchangeAlgorithm.RSA: + break; + + default: + /* Note: internal error here; selected a key exchange we don't implement! */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + X509KeyManager km = manager.getContextData().getKeyManager(); + if (km == null) + { + return null; + } + + short[] certTypes = certificateRequest.getCertificateTypes(); + if (certTypes == null || certTypes.length == 0) + { + // TODO[jsse] Or does this mean ANY type - or something else? + return null; + } + + String[] keyTypes = new String[certTypes.length]; + for (int i = 0; i < certTypes.length; ++i) + { + // TODO[jsse] Need to also take notice of certificateRequest.getSupportedSignatureAlgorithms(), if present + keyTypes[i] = JsseUtils.getClientAuthType(certTypes[i]); + } + + Principal[] issuers = null; + Vector cas = (Vector)certificateRequest.getCertificateAuthorities(); + if (cas != null && cas.size() > 0) + { + X500Name[] names = cas.toArray(new X500Name[cas.size()]); + Set principals = JsseUtils.toX500Principals(names); + issuers = principals.toArray(new Principal[principals.size()]); + } + + // TODO[jsse] How is this used? + Socket socket = null; + + String alias = km.chooseClientAlias(keyTypes, issuers, socket); + if (alias == null) + { + // TODO[jsse] Should sslParameters.getNeedClientAuth imply failing the handshake here? + return null; + } + + TlsCrypto crypto = getCrypto(); + if (!(crypto instanceof JcaTlsCrypto)) + { + // TODO[jsse] Need to have TlsCrypto construct the credentials from the certs/key + throw new UnsupportedOperationException(); + } + + PrivateKey privateKey = km.getPrivateKey(alias); + X509Certificate[] chain = km.getCertificateChain(alias); + Certificate certificate = JsseUtils.getCertificateMessage(crypto, chain); + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DH_RSA: + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDH_RSA: + { + // TODO[jsse] Need to have TlsCrypto construct the credentials from the certs/key + return new JceDefaultTlsCredentialedAgreement((JcaTlsCrypto)crypto, certificate, privateKey); + } + + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_RSA: + case KeyExchangeAlgorithm.ECDHE_ECDSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + case KeyExchangeAlgorithm.RSA: + { + short signatureAlgorithm = TlsUtils.getSignatureAlgorithm(keyExchangeAlgorithm); + SignatureAndHashAlgorithm sigAlg = TlsUtils.chooseSignatureAndHashAlgorithm(context, + supportedSignatureAlgorithms, signatureAlgorithm); + + // TODO[jsse] Need to have TlsCrypto construct the credentials from the certs/key + return new JcaDefaultTlsCredentialedSigner(new TlsCryptoParameters(context), (JcaTlsCrypto)crypto, + privateKey, certificate, sigAlg); + } + + default: + /* Note: internal error here; selected a key exchange we don't implement! */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public void notifyServerCertificate(Certificate serverCertificate) throws IOException + { + boolean noServerCert = serverCertificate == null || serverCertificate.isEmpty(); + if (noServerCert) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + else + { + X509Certificate[] chain = JsseUtils.getX509CertificateChain(serverCertificate); + String authType = JsseUtils.getAuthType(TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite)); + + if (!manager.isServerTrusted(chain, authType)) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + } + } + }; + } + + @Override + public int[] getCipherSuites() + { + return TlsUtils.getSupportedCipherSuites(manager.getContextData().getCrypto(), + manager.getContext().convertCipherSuites(sslParameters.getCipherSuites())); + } + +// public TlsKeyExchange getKeyExchange() throws IOException +// { +// // TODO[jsse] Check that all key exchanges used in JSSE supportedCipherSuites are handled +// return super.getKeyExchange(); +// } + + @Override + public ProtocolVersion getMinimumVersion() + { + return manager.getContext().getMinimumVersion(sslParameters.getProtocols()); + } + + @Override + public ProtocolVersion getClientVersion() + { + return manager.getContext().getMaximumVersion(sslParameters.getProtocols()); + } + + @Override + public TlsSession getSessionToResume() + { + // TODO[jsse] Search for a suitable session in the client session context + return null; + } + +// @Override +// public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) +// { +// PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; +// out.println("JSSE client raised alert: " + AlertLevel.getText(alertLevel) +// + ", " + AlertDescription.getText(alertDescription)); +// if (message != null) +// { +// out.println("> " + message); +// } +// if (cause != null) +// { +// cause.printStackTrace(out); +// } +// } + + @Override + public synchronized void notifyHandshakeComplete() throws IOException + { + this.handshakeComplete = true; + + ProvSSLSessionContext sessionContext = manager.getContextData().getClientSessionContext(); + SSLSession session = sessionContext.reportSession(context.getSession()); + + manager.notifyHandshakeComplete(session); + } + + @Override + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + String selected = manager.getContext().getProtocolString(serverVersion); + if (selected != null) + { + for (String protocol : sslParameters.getProtocols()) + { + if (selected.equals(protocol)) + { + return; + } + } + } + throw new TlsFatalAlert(AlertDescription.protocol_version); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsManager.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsManager.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsManager.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsManager.java 2016-12-09 02:34:48.000000000 +0000 @@ -0,0 +1,20 @@ +package org.bouncycastle.jsse.provider; + +import java.security.cert.X509Certificate; + +import javax.net.ssl.SSLSession; + +interface ProvTlsManager +{ + ProvSSLContextSpi getContext(); + + ProvSSLParameters getProvSSLParameters(); + + ContextData getContextData(); + + boolean isClientTrusted(X509Certificate[] chain, String authType); + + boolean isServerTrusted(X509Certificate[] chain, String authType); + + void notifyHandshakeComplete(SSLSession session); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsPeer.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsPeer.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsPeer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsPeer.java 2016-10-15 20:29:16.000000000 +0000 @@ -0,0 +1,6 @@ +package org.bouncycastle.jsse.provider; + +interface ProvTlsPeer +{ + boolean isHandshakeComplete(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsServer.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsServer.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsServer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsServer.java 2016-12-09 02:39:57.000000000 +0000 @@ -0,0 +1,268 @@ +package org.bouncycastle.jsse.provider; + +import java.io.IOException; +import java.net.Socket; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.Vector; + +import javax.net.ssl.SSLSession; +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.CertificateRequest; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.DefaultTlsServer; +import org.bouncycastle.tls.KeyExchangeAlgorithm; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsCredentials; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.impl.jcajce.JcaDefaultTlsCredentialedSigner; +import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto; +import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedAgreement; +import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedDecryptor; + +class ProvTlsServer + extends DefaultTlsServer + implements ProvTlsPeer +{ + protected final ProvTlsManager manager; + protected final ProvSSLParameters sslParameters; + + protected boolean handshakeComplete = false; + + ProvTlsServer(ProvTlsManager manager) + { + super(manager.getContextData().getCrypto()); + + this.manager = manager; + this.sslParameters = manager.getProvSSLParameters(); + } + + public synchronized boolean isHandshakeComplete() + { + return handshakeComplete; + } + + public TlsCredentials getCredentials() + throws IOException + { + int keyExchangeAlgorithm = TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite); + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DH_anon: + case KeyExchangeAlgorithm.ECDH_anon: + return null; + + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DH_RSA: + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_RSA: + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDH_RSA: + case KeyExchangeAlgorithm.ECDHE_ECDSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + case KeyExchangeAlgorithm.RSA: + break; + + default: + /* Note: internal error here; selected a key exchange we don't implement! */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + X509KeyManager km = manager.getContextData().getKeyManager(); + if (km == null) + { + return null; + } + + String keyType = JsseUtils.getAuthType(keyExchangeAlgorithm); + // TODO[jsse] Is there some extension where the client can specify these (SNI maybe)? + Principal[] issuers = null; + // TODO[jsse] How is this used? + Socket socket = null; + + String alias = km.chooseServerAlias(keyType, issuers, socket); + if (alias == null) + { + return null; + } + + TlsCrypto crypto = getCrypto(); + if (!(crypto instanceof JcaTlsCrypto)) + { + // TODO[jsse] Need to have TlsCrypto construct the credentials from the certs/key + throw new UnsupportedOperationException(); + } + + PrivateKey privateKey = km.getPrivateKey(alias); + Certificate certificate = JsseUtils.getCertificateMessage(crypto, km.getCertificateChain(alias)); + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DH_RSA: + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDH_RSA: + { + // TODO[jsse] Need to have TlsCrypto construct the credentials from the certs/key + return new JceDefaultTlsCredentialedAgreement((JcaTlsCrypto)crypto, certificate, privateKey); + } + + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_RSA: + case KeyExchangeAlgorithm.ECDHE_ECDSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + { + short signatureAlgorithm = TlsUtils.getSignatureAlgorithm(keyExchangeAlgorithm); + SignatureAndHashAlgorithm sigAlg = TlsUtils.chooseSignatureAndHashAlgorithm(context, + supportedSignatureAlgorithms, signatureAlgorithm); + + // TODO[jsse] Need to have TlsCrypto construct the credentials from the certs/key + return new JcaDefaultTlsCredentialedSigner(new TlsCryptoParameters(context), (JcaTlsCrypto)crypto, + privateKey, certificate, sigAlg); + } + + case KeyExchangeAlgorithm.RSA: + { + // TODO[jsse] Need to have TlsCrypto construct the credentials from the certs/key + return new JceDefaultTlsCredentialedDecryptor((JcaTlsCrypto)crypto, certificate, privateKey); + } + + default: + /* Note: internal error here; selected a key exchange we don't implement! */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public int[] getCipherSuites() + { + return TlsUtils.getSupportedCipherSuites(manager.getContextData().getCrypto(), + manager.getContext().convertCipherSuites(sslParameters.getCipherSuites())); + } + +// public TlsKeyExchange getKeyExchange() throws IOException +// { +// // TODO[jsse] Check that all key exchanges used in JSSE supportedCipherSuites are handled +// return super.getKeyExchange(); +// } + + @Override + public CertificateRequest getCertificateRequest() throws IOException + { + boolean shouldRequest = sslParameters.getNeedClientAuth() || sslParameters.getWantClientAuth(); + if (!shouldRequest) + { + return null; + } + + short[] certificateTypes = new short[]{ ClientCertificateType.rsa_sign, + ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign }; + + Vector serverSigAlgs = null; + if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(serverVersion)) + { + serverSigAlgs = TlsUtils.getDefaultSupportedSignatureAlgorithms(); + } + + Vector certificateAuthorities = new Vector(); + X509TrustManager tm = manager.getContextData().getTrustManager(); + if (tm != null) + { + for (X509Certificate caCert : tm.getAcceptedIssuers()) + { + certificateAuthorities.addElement(X500Name.getInstance(caCert.getSubjectX500Principal().getEncoded())); + } + } + + return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities); + } + +// @Override +// public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) +// { +// PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; +// out.println("JSSE server raised alert: " + AlertLevel.getText(alertLevel) +// + ", " + AlertDescription.getText(alertDescription)); +// if (message != null) +// { +// out.println("> " + message); +// } +// if (cause != null) +// { +// cause.printStackTrace(out); +// } +// } + + @Override + public ProtocolVersion getServerVersion() throws IOException + { + /* + * TODO[jsse] It may be best to just require the "protocols" list to be a contiguous set + * (especially in light of TLS_FALLBACK_SCSV), then just determine the minimum/maximum, + * and keep the super class implementation of this. + */ + String[] protocols = sslParameters.getProtocols(); + if (protocols != null && protocols.length > 0) + { + for (ProtocolVersion version = clientVersion; version != null; version = version.getPreviousVersion()) + { + String versionString = manager.getContext().getProtocolString(version); + if (versionString != null && JsseUtils.contains(protocols, versionString)) + { + return serverVersion = version; + } + } + } + throw new TlsFatalAlert(AlertDescription.protocol_version); + } + + @Override + public void notifyClientCertificate(Certificate clientCertificate) throws IOException + { + // NOTE: This method isn't called unless we returned non-null from getCertificateRequest() earlier + assert sslParameters.getNeedClientAuth() || sslParameters.getWantClientAuth(); + + boolean noClientCert = clientCertificate == null || clientCertificate.isEmpty(); + if (noClientCert) + { + if (sslParameters.getNeedClientAuth()) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + } + else + { + X509Certificate[] chain = JsseUtils.getX509CertificateChain(clientCertificate); + String authType = JsseUtils.getAuthType(TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite)); + + if (!manager.isClientTrusted(chain, authType)) + { + /* + * TODO[jsse] The low-level TLS API currently doesn't provide a way to indicate that + * we wish to proceed with an untrusted client certificate, so we always fail here. + */ + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + } + } + + @Override + public synchronized void notifyHandshakeComplete() throws IOException + { + this.handshakeComplete = true; + + ProvSSLSessionContext sessionContext = manager.getContextData().getServerSessionContext(); + SSLSession session = sessionContext.reportSession(context.getSession()); + + manager.notifyHandshakeComplete(session); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTrustManagerFactorySpi.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTrustManagerFactorySpi.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTrustManagerFactorySpi.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTrustManagerFactorySpi.java 2016-12-09 03:06:46.000000000 +0000 @@ -0,0 +1,65 @@ +package org.bouncycastle.jsse.provider; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.Provider; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactorySpi; +import javax.net.ssl.X509TrustManager; + +class ProvTrustManagerFactorySpi + extends TrustManagerFactorySpi +{ + static final boolean hasExtendedTrustManager; + + static + { + Class clazz = null; + try + { + clazz = ProvSSLServerSocket.class.getClassLoader().loadClass("javax.net.ssl.X509ExtendedTrustManager"); + } + catch (Exception e) + { + clazz = null; + } + + hasExtendedTrustManager = (clazz != null); + } + + protected final Provider pkixProvider; + + protected X509TrustManager trustManager; + + public ProvTrustManagerFactorySpi(Provider pkixProvider) + { + this.pkixProvider = pkixProvider; + } + + protected TrustManager[] engineGetTrustManagers() + { + return new TrustManager[]{ trustManager }; + } + + protected void engineInit(KeyStore ks) + throws KeyStoreException + { + if (hasExtendedTrustManager) + { + trustManager = new ProvX509ExtendedTrustManager(new ProvX509TrustManager(pkixProvider, ks)); + } + else + { + trustManager = new ProvX509TrustManager(pkixProvider, ks); + } + } + + protected void engineInit(ManagerFactoryParameters spec) + throws InvalidAlgorithmParameterException + { + throw new UnsupportedOperationException(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509ExtendedTrustManager.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509ExtendedTrustManager.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509ExtendedTrustManager.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509ExtendedTrustManager.java 2016-12-09 03:06:46.000000000 +0000 @@ -0,0 +1,69 @@ +package org.bouncycastle.jsse.provider; + +import java.net.Socket; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.X509ExtendedTrustManager; + +class ProvX509ExtendedTrustManager + extends X509ExtendedTrustManager +{ + private final ProvX509TrustManager trustManager; + + public ProvX509ExtendedTrustManager(ProvX509TrustManager trustManager) + { + this.trustManager = trustManager; + } + + public void checkClientTrusted(X509Certificate[] x509Certificates, String authType) + throws CertificateException + { + trustManager.checkClientTrusted(x509Certificates, authType); + } + + public void checkServerTrusted(X509Certificate[] x509Certificates, String authType) + throws CertificateException + { + trustManager.checkServerTrusted(x509Certificates, authType); + } + + public void checkClientTrusted(X509Certificate[] x509Certificates, String authType, Socket socket) + throws CertificateException + { + // TODO: need to confirm cert and client identity match + // TODO: need to make sure authType makes sense. + trustManager.validatePath(x509Certificates); + } + + public void checkServerTrusted(X509Certificate[] x509Certificates, String authType, Socket socket) + throws CertificateException + { + // TODO: need to confirm cert and server identity match + // TODO: need to make sure authType makes sense. + trustManager.validatePath(x509Certificates); + } + + public void checkClientTrusted(X509Certificate[] x509Certificates, String authType, SSLEngine sslEngine) + throws CertificateException + { + // TODO: need to confirm cert and client identity match + // TODO: need to make sure authType makes sense. + trustManager.validatePath(x509Certificates); + } + + public void checkServerTrusted(X509Certificate[] x509Certificates, String authType, SSLEngine sslEngine) + throws CertificateException + { + // TODO: need to confirm cert and server identity match + // TODO: need to make sure authType makes sense. + trustManager.validatePath(x509Certificates); + } + + + public X509Certificate[] getAcceptedIssuers() + { + return trustManager.getAcceptedIssuers(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509KeyManager.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509KeyManager.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509KeyManager.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509KeyManager.java 2016-12-09 23:02:16.000000000 +0000 @@ -0,0 +1,272 @@ +package org.bouncycastle.jsse.provider; + +import java.net.Socket; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.X509ExtendedKeyManager; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.asn1.x509.TBSCertificate; + +class ProvX509KeyManager + extends X509ExtendedKeyManager +{ + private final List builders; + + // TODO: does this need to be threadsafe? Will leak memory... + private final Map keys = new HashMap(); + + private final AtomicLong version = new AtomicLong(); + + public ProvX509KeyManager(List builders) + { + // the builder list is processed on request so the key manager is dynamic. + this.builders = builders; + } + + public String[] getClientAliases(String keyType, Principal[] issuers) + { + List aliases = findAliases(false, keyType, JsseUtils.toX500Names(issuers)); + + return aliases.toArray(new String[aliases.size()]); + } + + public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) + { + try + { + Set issuerNames = JsseUtils.toX500Names(issuers); + + // TODO[jsse] Need to support the keyTypes that SunJSSE sends here + for (int i = 0; i != keyTypes.length; i++) + { + List aliases = findAliases(false, keyTypes[i], issuerNames); + if (!aliases.isEmpty()) + { + return aliases.get(0); + } + } + + return null; + } + catch (Exception e) + { + return null; + } + } + + public String[] getServerAliases(String keyType, Principal[] issuers) + { + List aliases = findAliases(true, keyType, JsseUtils.toX500Names(issuers)); + + return aliases.toArray(new String[aliases.size()]); + } + + public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) + { + try + { + List aliases = findAliases(true, keyType, JsseUtils.toX500Names(issuers)); + + if (aliases.isEmpty()) + { + return null; + } + + return aliases.get(0); + } + catch (Exception e) + { + return null; + } + } + + public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) { + return null; + } + + public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { + return null; + } + + public X509Certificate[] getCertificateChain(String alias) + { + return (X509Certificate[])keys.get(alias).getCertificateChain(); + } + + public PrivateKey getPrivateKey(String alias) + { + return keys.get(alias).getPrivateKey(); + } + + private List findAliases(boolean forServer, String keyType, Set issuers) + { + List aliases = new ArrayList(); + + for (int i = 0; i != builders.size(); i++) + { + KeyStore.Builder builder = builders.get(i); + + try + { + aliases.addAll(findAliases(forServer, i, builder.getKeyStore(), builder, keyType, issuers)); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException("unable to build key store: " + e.getMessage(), e); + } + } + + return aliases; + } + + private List findAliases(boolean forServer, int index, KeyStore keyStore, KeyStore.Builder storeBuilder, String keyType, Set issuers) + throws GeneralSecurityException + { + List aliases = new ArrayList(); + + for (Enumeration en = keyStore.aliases(); en.hasMoreElements();) + { + String eName = (String)en.nextElement(); + + if (!keyStore.isKeyEntry(eName)) // not a key entry + { + continue; + } + + Certificate[] chain = keyStore.getCertificateChain(eName); + if (chain == null || chain.length == 0) // not an entry with a certificate + { + continue; + } + + if (!(chain[0] instanceof X509Certificate)) + { + continue; + } + + // scan back along the list of certificates + boolean found = false; + for (int i = chain.length - 1; i >= 0; i--) + { + X509Certificate x509Cert = (X509Certificate)chain[i]; + if (isSuitableCertificate(forServer, keyType, issuers, x509Cert)) + { + // TODO[jsse] Double-check the private key type here? + found = true; + break; + } + } + // TODO: manage two key/certs in one store that matches + + if (found) + { + KeyStore.PrivateKeyEntry kEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(eName, storeBuilder.getProtectionParameter(eName)); + + String alias = index + "." + eName + "." + version.getAndIncrement(); + + keys.put(alias, kEntry); + + aliases.add(alias); + } + } + + return aliases; + } + + private boolean isSuitableCertificate(boolean forServer, String keyType, Set issuers, X509Certificate c) + { + if (keyType == null || c == null) + { + return false; + } + if (!isSuitableIssuer(issuers, c)) + { + return false; + } + PublicKey pub = c.getPublicKey(); + if (keyType.equalsIgnoreCase("DHE_RSA") + || keyType.equalsIgnoreCase("ECDHE_RSA") + || keyType.equalsIgnoreCase("SRP_RSA")) + { + return (pub instanceof RSAPublicKey) && isSuitableKeyUsage(KeyUsage.digitalSignature, c); + } + if (keyType.equalsIgnoreCase("ECDHE_ECDSA")) + { + return (pub instanceof ECPublicKey) && isSuitableKeyUsage(KeyUsage.digitalSignature, c); + } + else if (keyType.equalsIgnoreCase("RSA")) + { + int keyUsage = forServer ? KeyUsage.keyEncipherment : KeyUsage.digitalSignature; + return (pub instanceof RSAPublicKey) && isSuitableKeyUsage(keyUsage, c); + } + else if (keyType.equalsIgnoreCase("DSA")) + { + return !forServer && (pub instanceof DSAPublicKey) && isSuitableKeyUsage(KeyUsage.digitalSignature, c); + } + else if (keyType.equalsIgnoreCase("EC")) + { + // NOTE: SunJSSE server asks for "EC" for ECDHE_ECDSA key exchange + return (pub instanceof ECPublicKey) && isSuitableKeyUsage(KeyUsage.digitalSignature, c); + } + // TODO[jsse] Support other key exchanges (and client certificate types) + return false; + } + + private boolean isSuitableIssuer(Set issuers, X509Certificate c) + { + try + { + org.bouncycastle.asn1.x509.Certificate asn1Cert = org.bouncycastle.asn1.x509.Certificate.getInstance(c.getEncoded()); + return issuers == null || issuers.isEmpty() || issuers.contains(asn1Cert.getIssuer()); + } + catch (Exception e) + { + return false; + } + } + + private boolean isSuitableKeyUsage(int keyUsageBits, X509Certificate c) + { + try + { + Extensions exts = TBSCertificate.getInstance(c.getTBSCertificate()).getExtensions(); + if (exts != null) + { + KeyUsage ku = KeyUsage.fromExtensions(exts); + if (ku != null) + { + int bits = ku.getBytes()[0] & 0xff; + if ((bits & keyUsageBits) != keyUsageBits) + { + return false; + } + } + } + } + catch (Exception e) + { + return false; + } + return true; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509TrustManager.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509TrustManager.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509TrustManager.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509TrustManager.java 2016-12-09 03:04:42.000000000 +0000 @@ -0,0 +1,101 @@ +package org.bouncycastle.jsse.provider; + +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.Provider; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; + +import javax.net.ssl.X509TrustManager; + +class ProvX509TrustManager + implements X509TrustManager +{ + private final Provider pkixProvider; + private final KeyStore trustStore; + + public ProvX509TrustManager(Provider pkixProvider, KeyStore trustStore) + { + this.pkixProvider = pkixProvider; + this.trustStore = trustStore; + } + + public void checkClientTrusted(X509Certificate[] x509Certificates, String authType) + throws CertificateException + { + // TODO: need to confirm cert and client identity match + // TODO: need to make sure authType makes sense. + validatePath(x509Certificates); + } + + public void checkServerTrusted(X509Certificate[] x509Certificates, String authType) + throws CertificateException + { + + // TODO: need to confirm cert and server identity match + // TODO: need to make sure authType makes sense. + validatePath(x509Certificates); + } + + public X509Certificate[] getAcceptedIssuers() + { + try + { + Set certs = new HashSet(trustStore.size()); + for (Enumeration en = trustStore.aliases(); en.hasMoreElements();) + { + String alias = (String)en.nextElement(); + if (trustStore.isCertificateEntry(alias)) + { + Certificate cert = trustStore.getCertificate(alias); + if (cert instanceof X509Certificate) + { + certs.add((X509Certificate)cert); + } + } + } + return certs.toArray(new X509Certificate[certs.size()]); + } + catch (Exception e) + { + return new X509Certificate[0]; + } + } + + protected void validatePath(X509Certificate[] x509Certificates) + throws CertificateException + { + try + { + CertStore certStore = CertStore.getInstance("Collection", + new CollectionCertStoreParameters(Arrays.asList(x509Certificates)), pkixProvider); + + CertPathBuilder pathBuilder = CertPathBuilder.getInstance("PKIX", pkixProvider); + + X509CertSelector constraints = new X509CertSelector(); + + constraints.setCertificate(x509Certificates[0]); + + PKIXBuilderParameters param = new PKIXBuilderParameters(trustStore, constraints); + param.addCertStore(certStore); + param.setRevocationEnabled(false); + + PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)pathBuilder.build(param); + } + catch (GeneralSecurityException e) + { + throw new CertificateException("unable to process certificates: " + e.getMessage(), e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/SessionBindingListenerAdapter.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/SessionBindingListenerAdapter.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/SessionBindingListenerAdapter.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/SessionBindingListenerAdapter.java 2016-09-26 00:53:43.000000000 +0000 @@ -0,0 +1,35 @@ +package org.bouncycastle.jsse.provider; + +import javax.net.ssl.SSLSessionBindingEvent; +import javax.net.ssl.SSLSessionBindingListener; + +class SessionBindingListenerAdapter + implements SSLSessionBindingListener +{ + protected final SSLSessionBindingListener listener; + + SessionBindingListenerAdapter(SSLSessionBindingListener listener) + { + this.listener = listener; + } + + public void valueBound(final SSLSessionBindingEvent event) + { + CallbackUtil.safeCallback(new Runnable(){ + public void run() + { + listener.valueBound(event); + } + }); + } + + public void valueUnbound(final SSLSessionBindingEvent event) + { + CallbackUtil.safeCallback(new Runnable(){ + public void run() + { + listener.valueUnbound(event); + } + }); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/SSLParametersUtil.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/SSLParametersUtil.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/jsse/provider/SSLParametersUtil.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/jsse/provider/SSLParametersUtil.java 2016-12-09 01:58:41.000000000 +0000 @@ -0,0 +1,64 @@ +package org.bouncycastle.jsse.provider; + +import javax.net.ssl.SSLParameters; + +public class SSLParametersUtil +{ + static SSLParameters toSSLParameters(ProvSSLParameters provSslParameters) + { + SSLParameters r = new SSLParameters(); + r.setCipherSuites(provSslParameters.getCipherSuites()); + r.setProtocols(provSslParameters.getProtocols()); + // TODO[jsse] From JDK 1.7 +// r.setAlgorithmConstraints(r.getAlgorithmConstraints()); +// r.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm()); + // TODO[jsse] From JDK 1.8 +// r.setServerNames(p.getServerNames()); +// r.setSNIMatchers(p.getSNIMatchers()); +// r.setUseCipherSuitesOrder(p.getUseCipherSuitesOrder()); + + // NOTE: The client-auth setters each clear the other client-auth property, so only one can be set + if (provSslParameters.getNeedClientAuth()) + { + r.setNeedClientAuth(true); + } + else if (provSslParameters.getWantClientAuth()) + { + r.setWantClientAuth(true); + } + else + { + r.setWantClientAuth(false); + } + return r; + } + + static ProvSSLParameters toProvSSLParameters(SSLParameters sslParameters) + { + ProvSSLParameters r = new ProvSSLParameters(); + r.setCipherSuites(sslParameters.getCipherSuites()); + r.setProtocols(sslParameters.getProtocols()); + // TODO[jsse] From JDK 1.7 +// r.setAlgorithmConstraints(r.getAlgorithmConstraints()); +// r.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm()); + // TODO[jsse] From JDK 1.8 +// r.setServerNames(p.getServerNames()); +// r.setSNIMatchers(p.getSNIMatchers()); +// r.setUseCipherSuitesOrder(p.getUseCipherSuitesOrder()); + + // NOTE: The client-auth setters each clear the other client-auth property, so only one can be set + if (sslParameters.getNeedClientAuth()) + { + r.setNeedClientAuth(true); + } + else if (sslParameters.getWantClientAuth()) + { + r.setWantClientAuth(true); + } + else + { + r.setWantClientAuth(false); + } + return r; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsClient.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsClient.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsClient.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsClient.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,274 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; + +public abstract class AbstractTlsClient + extends AbstractTlsPeer + implements TlsClient +{ + protected TlsKeyExchangeFactory keyExchangeFactory; + + protected TlsClientContext context; + + protected Vector supportedSignatureAlgorithms; + protected int[] namedCurves; + protected short[] clientECPointFormats, serverECPointFormats; + + protected int selectedCipherSuite; + protected short selectedCompressionMethod; + + public AbstractTlsClient(TlsCrypto crypto) + { + this(crypto, new DefaultTlsKeyExchangeFactory()); + } + + public AbstractTlsClient(TlsCrypto crypto, TlsKeyExchangeFactory keyExchangeFactory) + { + super(crypto); + + this.keyExchangeFactory = keyExchangeFactory; + } + + protected boolean allowUnexpectedServerExtension(Integer extensionType, byte[] extensionData) + throws IOException + { + switch (extensionType.intValue()) + { + case ExtensionType.supported_groups: + /* + * Exception added based on field reports that some servers do send this, although the + * Supported Elliptic Curves Extension is clearly intended to be client-only. If + * present, we still require that it is a valid EllipticCurveList. + */ + // TODO: restrict curve set using NamedCurve.FIPS if FIPS mode turned on. + TlsECCUtils.readSupportedEllipticCurvesExtension(extensionData, NamedCurve.ALL); + return true; + default: + return false; + } + } + + protected void checkForUnexpectedServerExtension(Hashtable serverExtensions, Integer extensionType) + throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(serverExtensions, extensionType); + if (extensionData != null && !allowUnexpectedServerExtension(extensionType, extensionData)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + + protected TlsECConfigVerifier createECConfigVerifier() + { + int minimumCurveBits = TlsECCUtils.getMinimumCurveBits(selectedCipherSuite); + return new DefaultTlsECConfigVerifier(minimumCurveBits, namedCurves); + } + + public void init(TlsClientContext context) + { + this.context = context; + } + + public TlsSession getSessionToResume() + { + return null; + } + + public ProtocolVersion getClientHelloRecordLayerVersion() + { + // "{03,00}" + // return ProtocolVersion.SSLv3; + + // "the lowest version number supported by the client" + // return getMinimumVersion(); + + // "the value of ClientHello.client_version" + return getClientVersion(); + } + + public ProtocolVersion getClientVersion() + { + return ProtocolVersion.TLSv12; + } + + public boolean isFallback() + { + /* + * RFC 7507 4. The TLS_FALLBACK_SCSV cipher suite value is meant for use by clients that + * repeat a connection attempt with a downgraded protocol (perform a "fallback retry") in + * order to work around interoperability problems with legacy servers. + */ + return false; + } + + public Hashtable getClientExtensions() + throws IOException + { + Hashtable clientExtensions = null; + + ProtocolVersion clientVersion = context.getClientVersion(); + + /* + * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior to 1.2. + * Clients MUST NOT offer it if they are offering prior versions. + */ + if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(clientVersion)) + { + // TODO Provide a way for the user to specify the acceptable hash/signature algorithms. + + this.supportedSignatureAlgorithms = TlsUtils.getDefaultSupportedSignatureAlgorithms(); + + clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(clientExtensions); + + TlsUtils.addSignatureAlgorithmsExtension(clientExtensions, supportedSignatureAlgorithms); + } + + if (TlsECCUtils.containsECCipherSuites(getCipherSuites())) + { + /* + * RFC 4492 5.1. A client that proposes ECC cipher suites in its ClientHello message + * appends these extensions (along with any others), enumerating the curves it supports + * and the point formats it can parse. Clients SHOULD send both the Supported Elliptic + * Curves Extension and the Supported Point Formats Extension. + */ + /* + * TODO Could just add all the curves since we support them all, but users may not want + * to use unnecessarily large fields. Need configuration options. + */ + this.namedCurves = new int[]{ NamedCurve.secp256r1, NamedCurve.secp384r1 }; + this.clientECPointFormats = new short[]{ ECPointFormat.uncompressed, + ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, }; + + clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(clientExtensions); + + TlsECCUtils.addSupportedEllipticCurvesExtension(clientExtensions, namedCurves); + TlsECCUtils.addSupportedPointFormatsExtension(clientExtensions, clientECPointFormats); + } + + return clientExtensions; + } + + public ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.TLSv10; + } + + public void notifyServerVersion(ProtocolVersion serverVersion) + throws IOException + { + if (!getMinimumVersion().isEqualOrEarlierVersionOf(serverVersion)) + { + throw new TlsFatalAlert(AlertDescription.protocol_version); + } + } + + public short[] getCompressionMethods() + { + return new short[]{CompressionMethod._null}; + } + + public void notifySessionID(byte[] sessionID) + { + // Currently ignored + } + + public void notifySelectedCipherSuite(int selectedCipherSuite) + { + this.selectedCipherSuite = selectedCipherSuite; + } + + public void notifySelectedCompressionMethod(short selectedCompressionMethod) + { + this.selectedCompressionMethod = selectedCompressionMethod; + } + + public void processServerExtensions(Hashtable serverExtensions) + throws IOException + { + /* + * TlsProtocol implementation validates that any server extensions received correspond to + * client extensions sent. By default, we don't send any, and this method is not called. + */ + if (serverExtensions != null) + { + /* + * RFC 5246 7.4.1.4.1. Servers MUST NOT send this extension. + */ + checkForUnexpectedServerExtension(serverExtensions, TlsUtils.EXT_signature_algorithms); + + checkForUnexpectedServerExtension(serverExtensions, TlsECCUtils.EXT_elliptic_curves); + + if (TlsECCUtils.isECCipherSuite(this.selectedCipherSuite)) + { + this.serverECPointFormats = TlsECCUtils.getSupportedPointFormatsExtension(serverExtensions); + } + else + { + checkForUnexpectedServerExtension(serverExtensions, TlsECCUtils.EXT_ec_point_formats); + } + + /* + * RFC 7685 3. The server MUST NOT echo the extension. + */ + checkForUnexpectedServerExtension(serverExtensions, TlsExtensionsUtils.EXT_padding); + } + } + + public void processServerSupplementalData(Vector serverSupplementalData) + throws IOException + { + if (serverSupplementalData != null) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + } + + public Vector getClientSupplementalData() + throws IOException + { + return null; + } + + public TlsCompression getCompression() + throws IOException + { + switch (selectedCompressionMethod) + { + case CompressionMethod._null: + return new TlsNullCompression(); + + default: + /* + * Note: internal error here; the TlsProtocol implementation verifies that the + * server-selected compression method was in the list of client-offered compression + * methods, so if we now can't produce an implementation, we shouldn't have offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public TlsCipher getCipher() + throws IOException + { + int encryptionAlgorithm = TlsUtils.getEncryptionAlgorithm(selectedCipherSuite); + int macAlgorithm = TlsUtils.getMACAlgorithm(selectedCipherSuite); + + if (encryptionAlgorithm < 0 || macAlgorithm < 0) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + return context.getSecurityParameters().getMasterSecret().createCipher(new TlsCryptoParameters(context), encryptionAlgorithm, macAlgorithm); + } + + public void notifyNewSessionTicket(NewSessionTicket newSessionTicket) + throws IOException + { + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsContext.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsContext.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsContext.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsContext.java 2016-11-21 00:44:31.000000000 +0000 @@ -0,0 +1,129 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsCrypto; + +abstract class AbstractTlsContext + implements TlsContext +{ + private TlsCrypto crypto; + private SecurityParameters securityParameters; + + private ProtocolVersion clientVersion = null; + private ProtocolVersion serverVersion = null; + private TlsSession session = null; + private Object userObject = null; + + AbstractTlsContext(TlsCrypto crypto, SecurityParameters securityParameters) + { + this.crypto = crypto; + this.securityParameters = securityParameters; + } + + public TlsCrypto getCrypto() + { + return crypto; + } + + public SecurityParameters getSecurityParameters() + { + return securityParameters; + } + + public ProtocolVersion getClientVersion() + { + return clientVersion; + } + + void setClientVersion(ProtocolVersion clientVersion) + { + this.clientVersion = clientVersion; + } + + public ProtocolVersion getServerVersion() + { + return serverVersion; + } + + void setServerVersion(ProtocolVersion serverVersion) + { + this.serverVersion = serverVersion; + } + + public TlsSession getResumableSession() + { + TlsSession session = getSession(); + if (session == null || !session.isResumable()) + { + return null; + } + return session; + } + + public TlsSession getSession() + { + return session; + } + + void setSession(TlsSession session) + { + this.session = session; + } + + public Object getUserObject() + { + return userObject; + } + + public void setUserObject(Object userObject) + { + this.userObject = userObject; + } + + public byte[] exportKeyingMaterial(String asciiLabel, byte[] context_value, int length) + { + /* + * TODO[session-hash] + * + * draft-ietf-tls-session-hash-04 5.4. If a client or server chooses to continue with a full + * handshake without the extended master secret extension, [..] the client or server MUST + * NOT export any key material based on the new master secret for any subsequent + * application-level authentication. In particular, it MUST disable [RFC5705] [..]. + */ + + if (context_value != null && !TlsUtils.isValidUint16(context_value.length)) + { + throw new IllegalArgumentException("'context_value' must have length less than 2^16 (or be null)"); + } + + SecurityParameters sp = getSecurityParameters(); + byte[] cr = sp.getClientRandom(), sr = sp.getServerRandom(); + + int seedLength = cr.length + sr.length; + if (context_value != null) + { + seedLength += (2 + context_value.length); + } + + byte[] seed = new byte[seedLength]; + int seedPos = 0; + + System.arraycopy(cr, 0, seed, seedPos, cr.length); + seedPos += cr.length; + System.arraycopy(sr, 0, seed, seedPos, sr.length); + seedPos += sr.length; + if (context_value != null) + { + TlsUtils.writeUint16(context_value.length, seed, seedPos); + seedPos += 2; + System.arraycopy(context_value, 0, seed, seedPos, context_value.length); + seedPos += context_value.length; + } + + if (seedPos != seedLength) + { + throw new IllegalStateException("error in calculation of seed for export"); + } + + return TlsUtils.PRF(this, sp.getMasterSecret(), asciiLabel, seed, length).extract(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchangeFactory.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchangeFactory.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchangeFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchangeFactory.java 2016-08-28 04:49:25.000000000 +0000 @@ -0,0 +1,92 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsECConfig; + +public class AbstractTlsKeyExchangeFactory + implements TlsKeyExchangeFactory +{ + public TlsKeyExchange createDHKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsDHConfigVerifier dhConfigVerifier) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createDHKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsDHConfig dhConfig) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createDHEKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsDHConfigVerifier dhConfigVerifier) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createDHEKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsDHConfig dhConfig) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createECDHKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfigVerifier ecConfigVerifier, short[] clientECPointFormats, short[] serverECPointFormats) + throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createECDHKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfig ecConfig, short[] serverECPointFormats) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createECDHEKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfigVerifier ecConfigVerifier, short[] clientECPointFormats, short[] serverECPointFormats) + throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createECDHEKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfig ecConfig, short[] serverECPointFormats) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createPSKKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsPSKIdentity pskIdentity, TlsDHConfigVerifier dhConfigVerifier, TlsECConfigVerifier ecConfigVerifier, + short[] clientECPointFormats, short[] serverECPointFormats) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createPSKKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsPSKIdentityManager pskIdentityManager, TlsDHConfig dhConfig, TlsECConfig ecConfig, + short[] serverECPointFormats) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createRSAKeyExchange(Vector supportedSignatureAlgorithms) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createSRPKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsSRPConfigVerifier srpConfigVerifier, byte[] identity, byte[] password) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsKeyExchange createSRPKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + byte[] identity, TlsSRPLoginParameters loginParameters) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchange.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchange.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchange.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchange.java 2016-08-28 04:49:25.000000000 +0000 @@ -0,0 +1,181 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Vector; + +public abstract class AbstractTlsKeyExchange + implements TlsKeyExchange +{ + protected int keyExchange; + protected Vector supportedSignatureAlgorithms; + + protected TlsContext context; + + protected AbstractTlsKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms) + { + this.keyExchange = keyExchange; + this.supportedSignatureAlgorithms = supportedSignatureAlgorithms; + } + + protected void checkServerCertSigAlg(Certificate serverCertificate) throws IOException + { + if (supportedSignatureAlgorithms == null) + { + /* + * TODO RFC 2246 7.4.2. Unless otherwise specified, the signing algorithm for the + * certificate must be the same as the algorithm for the certificate key. + */ + } + else + { + /* + * TODO RFC 5246 7.4.2. If the client provided a "signature_algorithms" extension, then + * all certificates provided by the server MUST be signed by a hash/signature algorithm + * pair that appears in that extension. + */ + } + } + + protected DigitallySigned parseSignature(InputStream input) throws IOException + { + DigitallySigned signature = DigitallySigned.parse(context, input); + SignatureAndHashAlgorithm signatureAlgorithm = signature.getAlgorithm(); + if (signatureAlgorithm != null) + { + TlsUtils.verifySupportedSignatureAlgorithm(supportedSignatureAlgorithms, signatureAlgorithm); + } + return signature; + } + + public void init(TlsContext context) + { + this.context = context; + + ProtocolVersion clientVersion = context.getClientVersion(); + + if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(clientVersion)) + { + /* + * RFC 5264 7.4.1.4.1. If the client does not send the signature_algorithms extension, + * the server MUST do the following: + * + * - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK, + * ECDH_RSA, ECDHE_RSA), behave as if client had sent the value {sha1,rsa}. + * + * - If the negotiated key exchange algorithm is one of (DHE_DSS, DH_DSS), behave as if + * the client had sent the value {sha1,dsa}. + * + * - If the negotiated key exchange algorithm is one of (ECDH_ECDSA, ECDHE_ECDSA), + * behave as if the client had sent value {sha1,ecdsa}. + */ + if (this.supportedSignatureAlgorithms == null) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.SRP_DSS: + { + this.supportedSignatureAlgorithms = TlsUtils.getDefaultDSSSignatureAlgorithms(); + break; + } + + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDHE_ECDSA: + { + this.supportedSignatureAlgorithms = TlsUtils.getDefaultECDSASignatureAlgorithms(); + break; + } + + case KeyExchangeAlgorithm.DH_RSA: + case KeyExchangeAlgorithm.DHE_RSA: + case KeyExchangeAlgorithm.ECDH_RSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + case KeyExchangeAlgorithm.RSA: + case KeyExchangeAlgorithm.RSA_PSK: + case KeyExchangeAlgorithm.SRP_RSA: + { + this.supportedSignatureAlgorithms = TlsUtils.getDefaultRSASignatureAlgorithms(); + break; + } + + case KeyExchangeAlgorithm.DHE_PSK: + case KeyExchangeAlgorithm.ECDHE_PSK: + case KeyExchangeAlgorithm.PSK: + case KeyExchangeAlgorithm.SRP: + break; + + default: + throw new IllegalStateException("unsupported key exchange algorithm"); + } + } + } + else if (this.supportedSignatureAlgorithms != null) + { + throw new IllegalStateException("supported_signature_algorithms not allowed for " + clientVersion); + } + } + + public void processServerCertificate(Certificate serverCertificate) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public void processServerCredentials(TlsCredentials serverCredentials) + throws IOException + { + // TODO[tls-ops] Process the server certificate differently on the server side + processServerCertificate(serverCredentials.getCertificate()); + } + + public boolean requiresServerKeyExchange() + { + return false; + } + + public byte[] generateServerKeyExchange() + throws IOException + { + if (requiresServerKeyExchange()) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + return null; + } + + public void skipServerKeyExchange() + throws IOException + { + if (requiresServerKeyExchange()) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + } + + public void processServerKeyExchange(InputStream input) + throws IOException + { + if (!requiresServerKeyExchange()) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + } + + public void skipClientCredentials() + throws IOException + { + } + + public void processClientCertificate(Certificate clientCertificate) + throws IOException + { + } + + public void processClientKeyExchange(InputStream input) + throws IOException + { + // Key exchange implementation MUST support client key exchange + throw new TlsFatalAlert(AlertDescription.internal_error); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsPeer.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsPeer.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsPeer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsPeer.java 2016-10-01 23:50:13.000000000 +0000 @@ -0,0 +1,56 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.TlsCrypto; + +public abstract class AbstractTlsPeer + implements TlsPeer +{ + private final TlsCrypto crypto; + + protected AbstractTlsPeer(TlsCrypto crypto) + { + this.crypto = crypto; + } + + public TlsCrypto getCrypto() + { + return crypto; + } + + public boolean shouldUseGMTUnixTime() + { + /* + * draft-mathewson-no-gmtunixtime-00 2. For the reasons we discuss above, we recommend that + * TLS implementors MUST by default set the entire value the ClientHello.Random and + * ServerHello.Random fields, including gmt_unix_time, to a cryptographically random + * sequence. + */ + return false; + } + + public void notifySecureRenegotiation(boolean secureRenegotiation) throws IOException + { + if (!secureRenegotiation) + { + /* + * RFC 5746 3.4/3.6. In this case, some clients/servers may want to terminate the handshake instead + * of continuing; see Section 4.1/4.3 for discussion. + */ + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + } + + public void notifyHandshakeComplete() throws IOException + { + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsServer.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsServer.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AbstractTlsServer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AbstractTlsServer.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,439 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.Set; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.DHGroup; +import org.bouncycastle.tls.crypto.DHStandardGroups; +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.util.Arrays; + +public abstract class AbstractTlsServer + extends AbstractTlsPeer + implements TlsServer +{ + protected TlsKeyExchangeFactory keyExchangeFactory; + + protected TlsServerContext context; + + protected ProtocolVersion clientVersion; + protected int[] offeredCipherSuites; + protected short[] offeredCompressionMethods; + protected Hashtable clientExtensions; + + protected boolean encryptThenMACOffered; + protected short maxFragmentLengthOffered; + protected boolean truncatedHMacOffered; + protected Vector supportedSignatureAlgorithms; + protected int[] namedCurves; + protected short[] clientECPointFormats, serverECPointFormats; + + protected ProtocolVersion serverVersion; + protected int selectedCipherSuite; + protected short selectedCompressionMethod; + protected Hashtable serverExtensions; + + public AbstractTlsServer(TlsCrypto crypto) + { + this(crypto, new DefaultTlsKeyExchangeFactory()); + } + + public AbstractTlsServer(TlsCrypto crypto, TlsKeyExchangeFactory keyExchangeFactory) + { + super(crypto); + + this.keyExchangeFactory = keyExchangeFactory; + } + + protected boolean allowEncryptThenMAC() + { + return true; + } + + protected boolean allowTruncatedHMac() + { + return false; + } + + protected Hashtable checkServerExtensions() + { + return this.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(this.serverExtensions); + } + + protected abstract int[] getCipherSuites(); + + protected short[] getCompressionMethods() + { + return new short[]{CompressionMethod._null}; + } + + protected DHGroup getDHParameters() + { + return DHStandardGroups.rfc3526_2048; + } + + protected ProtocolVersion getMaximumVersion() + { + return ProtocolVersion.TLSv12; + } + + protected ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.TLSv10; + } + + protected int getMaximumNegotiableCurveBits() + { + // NOTE: BC supports all the current set of point formats so we don't check them here + + if (namedCurves == null) + { + /* + * RFC 4492 4. A client that proposes ECC cipher suites may choose not to include these + * extensions. In this case, the server is free to choose any one of the elliptic curves + * or point formats [...]. + */ + return NamedCurve.getMaximumCurveBits(); + } + + int maxBits = 0; + for (int i = 0; i < namedCurves.length; ++i) + { + maxBits = Math.max(maxBits, NamedCurve.getCurveBits(namedCurves[i])); + } + return maxBits; + } + + protected int selectCurve(int minimumCurveBits) + { + if (namedCurves == null) + { + return selectDefaultCurve(minimumCurveBits); + } + + // Try to find a supported named curve of the required size from the client's list. + for (int i = 0; i < namedCurves.length; ++i) + { + int namedCurve = namedCurves[i]; + if (NamedCurve.getCurveBits(namedCurve) >= minimumCurveBits) + { + return namedCurve; + } + } + + return -1; + } + + protected int selectDefaultCurve(int minimumCurveBits) + { + // Note: this must all have a co-factor of 1 to qualify for FIPS ECDH. + return minimumCurveBits <= 256 ? NamedCurve.secp256r1 + : minimumCurveBits <= 384 ? NamedCurve.secp384r1 + : minimumCurveBits <= 521 ? NamedCurve.secp521r1 + : -1; + } + + protected TlsDHConfig selectDHConfig() + { + return TlsDHUtils.selectDHConfig(getDHParameters()); + } + + protected TlsECConfig selectECConfig() throws IOException + { + int minimumCurveBits = TlsECCUtils.getMinimumCurveBits(selectedCipherSuite); + + int namedCurve = selectCurve(minimumCurveBits); + if (namedCurve < 0) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + boolean compressed = TlsECCUtils.isCompressionPreferred(clientECPointFormats, namedCurve); + + TlsECConfig ecConfig = new TlsECConfig(); + ecConfig.setNamedCurve(namedCurve); + ecConfig.setPointCompression(compressed); + return ecConfig; + } + + public void init(TlsServerContext context) + { + this.context = context; + } + + public void notifyClientVersion(ProtocolVersion clientVersion) + throws IOException + { + this.clientVersion = clientVersion; + } + + public void notifyFallback(boolean isFallback) throws IOException + { + /* + * RFC 7507 3. If TLS_FALLBACK_SCSV appears in ClientHello.cipher_suites and the highest + * protocol version supported by the server is higher than the version indicated in + * ClientHello.client_version, the server MUST respond with a fatal inappropriate_fallback + * alert [..]. + */ + if (isFallback && getMaximumVersion().isLaterVersionOf(clientVersion)) + { + throw new TlsFatalAlert(AlertDescription.inappropriate_fallback); + } + } + + public void notifyOfferedCipherSuites(int[] offeredCipherSuites) + throws IOException + { + this.offeredCipherSuites = offeredCipherSuites; + } + + public void notifyOfferedCompressionMethods(short[] offeredCompressionMethods) + throws IOException + { + this.offeredCompressionMethods = offeredCompressionMethods; + } + + public void processClientExtensions(Hashtable clientExtensions) + throws IOException + { + this.clientExtensions = clientExtensions; + + if (clientExtensions != null) + { + this.encryptThenMACOffered = TlsExtensionsUtils.hasEncryptThenMACExtension(clientExtensions); + + this.maxFragmentLengthOffered = TlsExtensionsUtils.getMaxFragmentLengthExtension(clientExtensions); + if (maxFragmentLengthOffered >= 0 && !MaxFragmentLength.isValid(maxFragmentLengthOffered)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + this.truncatedHMacOffered = TlsExtensionsUtils.hasTruncatedHMacExtension(clientExtensions); + + this.supportedSignatureAlgorithms = TlsUtils.getSignatureAlgorithmsExtension(clientExtensions); + if (this.supportedSignatureAlgorithms != null) + { + /* + * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior + * to 1.2. Clients MUST NOT offer it if they are offering prior versions. + */ + if (!TlsUtils.isSignatureAlgorithmsExtensionAllowed(clientVersion)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + // TODO: restrict curve set using NamedCurve.FIPS if FIPS mode turned on. + Set acceptedCurves = NamedCurve.ALL; + + this.namedCurves = TlsECCUtils.getSupportedEllipticCurvesExtension(clientExtensions, acceptedCurves); + this.clientECPointFormats = TlsECCUtils.getSupportedPointFormatsExtension(clientExtensions); + } + + /* + * RFC 4429 4. The client MUST NOT include these extensions in the ClientHello message if it + * does not propose any ECC cipher suites. + * + * NOTE: This was overly strict as there may be ECC cipher suites that we don't recognize. + * Also, draft-ietf-tls-negotiated-ff-dhe will be overloading the 'elliptic_curves' + * extension to explicitly allow FFDHE (i.e. non-ECC) groups. + */ +// if (!this.eccCipherSuitesOffered && (this.namedCurves != null || this.clientECPointFormats != null)) +// { +// throw new TlsFatalAlert(AlertDescription.illegal_parameter); +// } + } + + public ProtocolVersion getServerVersion() + throws IOException + { + if (getMinimumVersion().isEqualOrEarlierVersionOf(clientVersion)) + { + ProtocolVersion maximumVersion = getMaximumVersion(); + if (clientVersion.isEqualOrEarlierVersionOf(maximumVersion)) + { + return serverVersion = clientVersion; + } + if (clientVersion.isLaterVersionOf(maximumVersion)) + { + return serverVersion = maximumVersion; + } + } + throw new TlsFatalAlert(AlertDescription.protocol_version); + } + + public int getSelectedCipherSuite() + throws IOException + { + /* + * TODO[tls-ops] Expedite the TODO below. Additionally, the signature algorithms need to be + * first pruned based on the signing credentials that are actually available. + * + * TODO RFC 5246 7.4.3. In order to negotiate correctly, the server MUST check any candidate + * cipher suites against the "signature_algorithms" extension before selecting them. This is + * somewhat inelegant but is a compromise designed to minimize changes to the original + * cipher suite design. + */ + + /* + * RFC 4429 5.1. A server that receives a ClientHello containing one or both of these + * extensions MUST use the client's enumerated capabilities to guide its selection of an + * appropriate cipher suite. One of the proposed ECC cipher suites must be negotiated only + * if the server can successfully complete the handshake while using the curves and point + * formats supported by the client [...]. + */ + int availCurveBits = getMaximumNegotiableCurveBits(); + + int[] cipherSuites = getCipherSuites(); + for (int i = 0; i < cipherSuites.length; ++i) + { + int cipherSuite = cipherSuites[i]; + + if (Arrays.contains(this.offeredCipherSuites, cipherSuite) + && TlsUtils.isValidCipherSuiteForVersion(cipherSuite, serverVersion) + && availCurveBits >= TlsECCUtils.getMinimumCurveBits(cipherSuite)) + { + return this.selectedCipherSuite = cipherSuite; + } + } + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + public short getSelectedCompressionMethod() + throws IOException + { + short[] compressionMethods = getCompressionMethods(); + for (int i = 0; i < compressionMethods.length; ++i) + { + if (Arrays.contains(offeredCompressionMethods, compressionMethods[i])) + { + return this.selectedCompressionMethod = compressionMethods[i]; + } + } + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + // Hashtable is (Integer -> byte[]) + public Hashtable getServerExtensions() + throws IOException + { + if (this.encryptThenMACOffered && allowEncryptThenMAC()) + { + /* + * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client + * and then selects a stream or Authenticated Encryption with Associated Data (AEAD) + * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the + * client. + */ + if (TlsUtils.isBlockCipherSuite(this.selectedCipherSuite)) + { + TlsExtensionsUtils.addEncryptThenMACExtension(checkServerExtensions()); + } + } + + if (this.maxFragmentLengthOffered >= 0 && MaxFragmentLength.isValid(maxFragmentLengthOffered)) + { + TlsExtensionsUtils.addMaxFragmentLengthExtension(checkServerExtensions(), this.maxFragmentLengthOffered); + } + + if (this.truncatedHMacOffered && allowTruncatedHMac()) + { + TlsExtensionsUtils.addTruncatedHMacExtension(checkServerExtensions()); + } + + if (this.clientECPointFormats != null && TlsECCUtils.isECCipherSuite(this.selectedCipherSuite)) + { + /* + * RFC 4492 5.2. A server that selects an ECC cipher suite in response to a ClientHello + * message including a Supported Point Formats Extension appends this extension (along + * with others) to its ServerHello message, enumerating the point formats it can parse. + */ + this.serverECPointFormats = new short[]{ ECPointFormat.uncompressed, + ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, }; + + TlsECCUtils.addSupportedPointFormatsExtension(checkServerExtensions(), serverECPointFormats); + } + + return serverExtensions; + } + + public Vector getServerSupplementalData() + throws IOException + { + return null; + } + + public CertificateStatus getCertificateStatus() + throws IOException + { + return null; + } + + public CertificateRequest getCertificateRequest() + throws IOException + { + return null; + } + + public void processClientSupplementalData(Vector clientSupplementalData) + throws IOException + { + if (clientSupplementalData != null) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + } + + public void notifyClientCertificate(Certificate clientCertificate) + throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public TlsCompression getCompression() + throws IOException + { + switch (selectedCompressionMethod) + { + case CompressionMethod._null: + return new TlsNullCompression(); + + default: + /* + * Note: internal error here; we selected the compression method, so if we now can't + * produce an implementation, we shouldn't have chosen it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public TlsCipher getCipher() + throws IOException + { + int encryptionAlgorithm = TlsUtils.getEncryptionAlgorithm(selectedCipherSuite); + int macAlgorithm = TlsUtils.getMACAlgorithm(selectedCipherSuite); + + if (encryptionAlgorithm < 0 || macAlgorithm < 0) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + return context.getSecurityParameters().getMasterSecret().createCipher(new TlsCryptoParameters(context), encryptionAlgorithm, macAlgorithm); + } + + public NewSessionTicket getNewSessionTicket() + throws IOException + { + /* + * RFC 5077 3.3. If the server determines that it does not want to include a ticket after it + * has included the SessionTicket extension in the ServerHello, then it sends a zero-length + * ticket in the NewSessionTicket handshake message. + */ + return new NewSessionTicket(0L, TlsUtils.EMPTY_BYTES); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AlertDescription.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AlertDescription.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AlertDescription.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AlertDescription.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,303 @@ +package org.bouncycastle.tls; + +/** + * RFC 5246 7.2. + */ +public class AlertDescription +{ + /** + * This message notifies the recipient that the sender will not send any more messages on this + * connection. Note that as of TLS 1.1, failure to properly close a connection no longer + * requires that a session not be resumed. This is a change from TLS 1.0 ("The session becomes + * unresumable if any connection is terminated without proper close_notify messages with level + * equal to warning.") to conform with widespread implementation practice. + */ + public static final short close_notify = 0; + + /** + * An inappropriate message was received. This alert is always fatal and should never be + * observed in communication between proper implementations. + */ + public static final short unexpected_message = 10; + + /** + * This alert is returned if a record is received with an incorrect MAC. This alert also MUST be + * returned if an alert is sent because a TLSCiphertext decrypted in an invalid way: either it + * wasn't an even multiple of the block length, or its padding values, when checked, weren't + * correct. This message is always fatal and should never be observed in communication between + * proper implementations (except when messages were corrupted in the network). + */ + public static final short bad_record_mac = 20; + + /** + * This alert was used in some earlier versions of TLS, and may have permitted certain attacks + * against the CBC mode [CBCATT]. It MUST NOT be sent by compliant implementations. + */ + public static final short decryption_failed = 21; + + /** + * A TLSCiphertext record was received that had a length more than 2^14+2048 bytes, or a record + * decrypted to a TLSCompressed record with more than 2^14+1024 bytes. This message is always + * fatal and should never be observed in communication between proper implementations (except + * when messages were corrupted in the network). + */ + public static final short record_overflow = 22; + + /** + * The decompression function received improper input (e.g., data that would expand to excessive + * length). This message is always fatal and should never be observed in communication between + * proper implementations. + */ + public static final short decompression_failure = 30; + + /** + * Reception of a handshake_failure alert message indicates that the sender was unable to + * negotiate an acceptable set of security parameters given the options available. This is a + * fatal error. + */ + public static final short handshake_failure = 40; + + /** + * This alert was used in SSLv3 but not any version of TLS. It MUST NOT be sent by compliant + * implementations. + */ + public static final short no_certificate = 41; + + /** + * A certificate was corrupt, contained signatures that did not verify correctly, etc. + */ + public static final short bad_certificate = 42; + + /** + * A certificate was of an unsupported type. + */ + public static final short unsupported_certificate = 43; + + /** + * A certificate was revoked by its signer. + */ + public static final short certificate_revoked = 44; + + /** + * A certificate has expired or is not currently valid. + */ + public static final short certificate_expired = 45; + + /** + * Some other (unspecified) issue arose in processing the certificate, rendering it + * unacceptable. + */ + public static final short certificate_unknown = 46; + + /** + * A field in the handshake was out of range or inconsistent with other fields. This message is + * always fatal. + */ + public static final short illegal_parameter = 47; + + /** + * A valid certificate chain or partial chain was received, but the certificate was not accepted + * because the CA certificate could not be located or couldn't be matched with a known, trusted + * CA. This message is always fatal. + */ + public static final short unknown_ca = 48; + + /** + * A valid certificate was received, but when access control was applied, the sender decided not + * to proceed with negotiation. This message is always fatal. + */ + public static final short access_denied = 49; + + /** + * A message could not be decoded because some field was out of the specified range or the + * length of the message was incorrect. This message is always fatal and should never be + * observed in communication between proper implementations (except when messages were corrupted + * in the network). + */ + public static final short decode_error = 50; + + /** + * A handshake cryptographic operation failed, including being unable to correctly verify a + * signature or validate a Finished message. This message is always fatal. + */ + public static final short decrypt_error = 51; + + /** + * This alert was used in some earlier versions of TLS. It MUST NOT be sent by compliant + * implementations. + */ + public static final short export_restriction = 60; + + /** + * The protocol version the client has attempted to negotiate is recognized but not supported. + * (For example, old protocol versions might be avoided for security reasons.) This message is + * always fatal. + */ + public static final short protocol_version = 70; + + /** + * Returned instead of handshake_failure when a negotiation has failed specifically because the + * server requires ciphers more secure than those supported by the client. This message is + * always fatal. + */ + public static final short insufficient_security = 71; + + /** + * An internal error unrelated to the peer or the correctness of the protocol (such as a memory + * allocation failure) makes it impossible to continue. This message is always fatal. + */ + public static final short internal_error = 80; + + /** + * This handshake is being canceled for some reason unrelated to a protocol failure. If the user + * cancels an operation after the handshake is complete, just closing the connection by sending + * a close_notify is more appropriate. This alert should be followed by a close_notify. This + * message is generally a warning. + */ + public static final short user_canceled = 90; + + /** + * Sent by the client in response to a hello request or by the server in response to a client + * hello after initial handshaking. Either of these would normally lead to renegotiation; when + * that is not appropriate, the recipient should respond with this alert. At that point, the + * original requester can decide whether to proceed with the connection. One case where this + * would be appropriate is where a server has spawned a process to satisfy a request; the + * process might receive security parameters (key length, authentication, etc.) at startup, and + * it might be difficult to communicate changes to these parameters after that point. This + * message is always a warning. + */ + public static final short no_renegotiation = 100; + + /** + * Sent by clients that receive an extended server hello containing an extension that they did + * not put in the corresponding client hello. This message is always fatal. + */ + public static final short unsupported_extension = 110; + + /* + * RFC 3546 + */ + + /** + * This alert is sent by servers who are unable to retrieve a certificate chain from the URL + * supplied by the client (see Section 3.3). This message MAY be fatal - for example if client + * authentication is required by the server for the handshake to continue and the server is + * unable to retrieve the certificate chain, it may send a fatal alert. + */ + public static final short certificate_unobtainable = 111; + + /** + * This alert is sent by servers that receive a server_name extension request, but do not + * recognize the server name. This message MAY be fatal. + */ + public static final short unrecognized_name = 112; + + /** + * This alert is sent by clients that receive an invalid certificate status response (see + * Section 3.6). This message is always fatal. + */ + public static final short bad_certificate_status_response = 113; + + /** + * This alert is sent by servers when a certificate hash does not match a client provided + * certificate_hash. This message is always fatal. + */ + public static final short bad_certificate_hash_value = 114; + + /* + * RFC 4279 + */ + + /** + * If the server does not recognize the PSK identity, it MAY respond with an + * "unknown_psk_identity" alert message. + */ + public static final short unknown_psk_identity = 115; + + /* + * RFC 7507 + */ + + /** + * If TLS_FALLBACK_SCSV appears in ClientHello.cipher_suites and the highest protocol version + * supported by the server is higher than the version indicated in ClientHello.client_version, + * the server MUST respond with a fatal inappropriate_fallback alert [..]. + */ + public static final short inappropriate_fallback = 86; + + public static String getName(short alertDescription) + { + switch (alertDescription) + { + case close_notify: + return "close_notify"; + case unexpected_message: + return "unexpected_message"; + case bad_record_mac: + return "bad_record_mac"; + case decryption_failed: + return "decryption_failed"; + case record_overflow: + return "record_overflow"; + case decompression_failure: + return "decompression_failure"; + case handshake_failure: + return "handshake_failure"; + case no_certificate: + return "no_certificate"; + case bad_certificate: + return "bad_certificate"; + case unsupported_certificate: + return "unsupported_certificate"; + case certificate_revoked: + return "certificate_revoked"; + case certificate_expired: + return "certificate_expired"; + case certificate_unknown: + return "certificate_unknown"; + case illegal_parameter: + return "illegal_parameter"; + case unknown_ca: + return "unknown_ca"; + case access_denied: + return "access_denied"; + case decode_error: + return "decode_error"; + case decrypt_error: + return "decrypt_error"; + case export_restriction: + return "export_restriction"; + case protocol_version: + return "protocol_version"; + case insufficient_security: + return "insufficient_security"; + case internal_error: + return "internal_error"; + case user_canceled: + return "user_canceled"; + case no_renegotiation: + return "no_renegotiation"; + case unsupported_extension: + return "unsupported_extension"; + case certificate_unobtainable: + return "certificate_unobtainable"; + case unrecognized_name: + return "unrecognized_name"; + case bad_certificate_status_response: + return "bad_certificate_status_response"; + case bad_certificate_hash_value: + return "bad_certificate_hash_value"; + case unknown_psk_identity: + return "unknown_psk_identity"; + case inappropriate_fallback: + return "inappropriate_fallback"; + default: + return "UNKNOWN"; + } + } + + public static String getText(short alertDescription) + { + return getName(alertDescription) + "(" + alertDescription + ")"; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AlertLevel.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AlertLevel.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/AlertLevel.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/AlertLevel.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,28 @@ +package org.bouncycastle.tls; + +/** + * RFC 5246 7.2 + */ +public class AlertLevel +{ + public static final short warning = 1; + public static final short fatal = 2; + + public static String getName(short alertDescription) + { + switch (alertDescription) + { + case warning: + return "warning"; + case fatal: + return "fatal"; + default: + return "UNKNOWN"; + } + } + + public static String getText(short alertDescription) + { + return getName(alertDescription) + "(" + alertDescription + ")"; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/BasicTlsPSKIdentity.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/BasicTlsPSKIdentity.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/BasicTlsPSKIdentity.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/BasicTlsPSKIdentity.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,42 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +public class BasicTlsPSKIdentity + implements TlsPSKIdentity +{ + protected byte[] identity; + protected byte[] psk; + + public BasicTlsPSKIdentity(byte[] identity, byte[] psk) + { + this.identity = Arrays.clone(identity); + this.psk = Arrays.clone(psk); + } + + public BasicTlsPSKIdentity(String identity, byte[] psk) + { + this.identity = Strings.toUTF8ByteArray(identity); + this.psk = Arrays.clone(psk); + } + + public void skipIdentityHint() + { + } + + public void notifyIdentityHint(byte[] psk_identity_hint) + { + } + + public byte[] getPSKIdentity() + { + return identity; + } + + public byte[] getPSK() + { + return psk; + } + +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/BulkCipherAlgorithm.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/BulkCipherAlgorithm.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/BulkCipherAlgorithm.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/BulkCipherAlgorithm.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,23 @@ +package org.bouncycastle.tls; + +/** + * RFC 2246 + *

      + * Note that the values here are implementation-specific and arbitrary. It is recommended not to + * depend on the particular values (e.g. serialization). + */ +public class BulkCipherAlgorithm +{ + public static final int _null = 0; + public static final int rc4 = 1; + public static final int rc2 = 2; + public static final int des = 3; + public static final int _3des = 4; + public static final int des40 = 5; + + /* + * RFC 4346 + */ + public static final int aes = 6; + public static final int idea = 7; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ByteQueueInputStream.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ByteQueueInputStream.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ByteQueueInputStream.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ByteQueueInputStream.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,63 @@ +package org.bouncycastle.tls; + +import java.io.InputStream; + +public class ByteQueueInputStream + extends InputStream +{ + private ByteQueue buffer; + + public ByteQueueInputStream() + { + buffer = new ByteQueue(); + } + + public void addBytes(byte[] bytes) + { + buffer.addData(bytes, 0, bytes.length); + } + + public int peek(byte[] buf) + { + int bytesToRead = Math.min(buffer.available(), buf.length); + buffer.read(buf, 0, bytesToRead, 0); + return bytesToRead; + } + + public int read() + { + if (buffer.available() == 0) + { + return -1; + } + return buffer.removeData(1, 0)[0] & 0xFF; + } + + public int read(byte[] b) + { + return read(b, 0, b.length); + } + + public int read(byte[] b, int off, int len) + { + int bytesToRead = Math.min(buffer.available(), len); + buffer.removeData(b, off, bytesToRead, 0); + return bytesToRead; + } + + public long skip(long n) + { + int bytesToRemove = Math.min((int)n, buffer.available()); + buffer.removeData(bytesToRemove); + return bytesToRemove; + } + + public int available() + { + return buffer.available(); + } + + public void close() + { + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ByteQueue.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ByteQueue.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ByteQueue.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ByteQueue.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,161 @@ +package org.bouncycastle.tls; + +/** + * A queue for bytes. This file could be more optimized. + */ +public class ByteQueue +{ + /** + * @return The smallest number which can be written as 2^x which is bigger than i. + */ + public static int nextTwoPow(int i) + { + /* + * This code is based of a lot of code I found on the Internet which mostly + * referenced a book called "Hacking delight". + */ + i |= (i >> 1); + i |= (i >> 2); + i |= (i >> 4); + i |= (i >> 8); + i |= (i >> 16); + return i + 1; + } + + /** + * The initial size for our buffer. + */ + private static final int DEFAULT_CAPACITY = 1024; + + /** + * The buffer where we store our data. + */ + private byte[] databuf; + + /** + * How many bytes at the beginning of the buffer are skipped. + */ + private int skipped = 0; + + /** + * How many bytes in the buffer are valid data. + */ + private int available = 0; + + public ByteQueue() + { + this(DEFAULT_CAPACITY); + } + + public ByteQueue(int capacity) + { + databuf = new byte[capacity]; + } + + /** + * Read data from the buffer. + * + * @param buf The buffer where the read data will be copied to. + * @param offset How many bytes to skip at the beginning of buf. + * @param len How many bytes to read at all. + * @param skip How many bytes from our data to skip. + */ + public void read(byte[] buf, int offset, int len, int skip) + { + if ((buf.length - offset) < len) + { + throw new IllegalArgumentException("Buffer size of " + buf.length + + " is too small for a read of " + len + " bytes"); + } + if ((available - skip) < len) + { + throw new IllegalStateException("Not enough data to read"); + } + System.arraycopy(databuf, skipped + skip, buf, offset, len); + } + + /** + * Add some data to our buffer. + * + * @param buf A byte-array to read data from. + * @param off How many bytes to skip at the beginning of the array. + * @param len How many bytes to read from the array. + */ + public void addData(byte[] buf, int off, int len) + { + if ((skipped + available + len) > databuf.length) + { + int desiredSize = ByteQueue.nextTwoPow(available + len); + if (desiredSize > databuf.length) + { + byte[] tmp = new byte[desiredSize]; + System.arraycopy(databuf, skipped, tmp, 0, available); + databuf = tmp; + } + else + { + System.arraycopy(databuf, skipped, databuf, 0, available); + } + skipped = 0; + } + + System.arraycopy(buf, off, databuf, skipped + available, len); + available += len; + } + + /** + * Remove some bytes from our data from the beginning. + * + * @param i How many bytes to remove. + */ + public void removeData(int i) + { + if (i > available) + { + throw new IllegalStateException("Cannot remove " + i + " bytes, only got " + available); + } + + /* + * Skip the data. + */ + available -= i; + skipped += i; + } + + /** + * Remove data from the buffer. + * + * @param buf The buffer where the removed data will be copied to. + * @param off How many bytes to skip at the beginning of buf. + * @param len How many bytes to read at all. + * @param skip How many bytes from our data to skip. + */ + public void removeData(byte[] buf, int off, int len, int skip) + { + read(buf, off, len, skip); + removeData(skip + len); + } + + public byte[] removeData(int len, int skip) + { + byte[] buf = new byte[len]; + removeData(buf, 0, len, skip); + return buf; + } + + /** + * @deprecated Use 'available' instead + */ + public int size() + { + return available; + } + + /** + * @return The number of bytes which are available in this buffer. + */ + public int available() + { + return available; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ByteQueueOutputStream.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ByteQueueOutputStream.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ByteQueueOutputStream.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ByteQueueOutputStream.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,30 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.OutputStream; + +public class ByteQueueOutputStream + extends OutputStream +{ + private ByteQueue buffer; + + public ByteQueueOutputStream() + { + buffer = new ByteQueue(); + } + + public ByteQueue getBuffer() + { + return buffer; + } + + public void write(int b) throws IOException + { + buffer.addData(new byte[]{ (byte)b }, 0, 1); + } + + public void write(byte[] b, int off, int len) throws IOException + { + buffer.addData(b, off, len); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertChainType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertChainType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertChainType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertChainType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,15 @@ +package org.bouncycastle.tls; + +/* + * RFC 3546 3.3. + */ +public class CertChainType +{ + public static final short individual_certs = 0; + public static final short pkipath = 1; + + public static boolean isValid(short certChainType) + { + return certChainType >= individual_certs && certChainType <= pkipath; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/Certificate.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/Certificate.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/Certificate.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/Certificate.java 2016-10-04 18:54:30.000000000 +0000 @@ -0,0 +1,137 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsCertificate; + +/** + * Parsing and encoding of a Certificate struct from RFC 4346. + *

      + * opaque ASN.1Cert<2^24-1>;
      + *
      + * struct {
      + *     ASN.1Cert certificate_list<0..2^24-1>;
      + * } Certificate;
      + * 
      + * + * @see org.bouncycastle.asn1.x509.Certificate + */ +public class Certificate +{ + public static final Certificate EMPTY_CHAIN = new Certificate(new TlsCertificate[0]); + + protected TlsCertificate[] certificateList; + + public Certificate(TlsCertificate[] certificateList) + { + if (certificateList == null) + { + throw new IllegalArgumentException("'certificateList' cannot be null"); + } + + this.certificateList = certificateList; + } + + /** + * @return an array of {@link org.bouncycastle.asn1.x509.Certificate} representing a certificate + * chain. + */ + public TlsCertificate[] getCertificateList() + { + return cloneCertificateList(); + } + + public TlsCertificate getCertificateAt(int index) + { + return certificateList[index]; + } + + public int getLength() + { + return certificateList.length; + } + + /** + * @return true if this certificate chain contains no certificates, or + * false otherwise. + */ + public boolean isEmpty() + { + return certificateList.length == 0; + } + + /** + * Encode this {@link Certificate} to an {@link OutputStream}. + * + * @param output the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) + throws IOException + { + Vector derEncodings = new Vector(this.certificateList.length); + + int totalLength = 0; + for (int i = 0; i < this.certificateList.length; ++i) + { + byte[] derEncoding = certificateList[i].getEncoded(); + derEncodings.addElement(derEncoding); + totalLength += derEncoding.length + 3; + } + + TlsUtils.checkUint24(totalLength); + TlsUtils.writeUint24(totalLength, output); + + for (int i = 0; i < derEncodings.size(); ++i) + { + byte[] derEncoding = (byte[])derEncodings.elementAt(i); + TlsUtils.writeOpaque24(derEncoding, output); + } + } + + /** + * Parse a {@link Certificate} from an {@link InputStream}. + * + * @param input the {@link InputStream} to parse from. + * @return a {@link Certificate} object. + * @throws IOException + */ + public static Certificate parse(TlsContext context, InputStream input) + throws IOException + { + int totalLength = TlsUtils.readUint24(input); + if (totalLength == 0) + { + return EMPTY_CHAIN; + } + + byte[] certListData = TlsUtils.readFully(totalLength, input); + + ByteArrayInputStream buf = new ByteArrayInputStream(certListData); + + Vector certificate_list = new Vector(); + while (buf.available() > 0) + { + byte[] derEncoding = TlsUtils.readOpaque24(buf); + certificate_list.addElement(context.getCrypto().createCertificate(derEncoding)); + } + + TlsCertificate[] certificateList = new TlsCertificate[certificate_list.size()]; + for (int i = 0; i < certificate_list.size(); i++) + { + certificateList[i] = (TlsCertificate)certificate_list.elementAt(i); + } + return new Certificate(certificateList); + } + + protected TlsCertificate[] cloneCertificateList() + { + TlsCertificate[] result = new TlsCertificate[certificateList.length]; + System.arraycopy(certificateList, 0, result, 0, result.length); + return result; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateRequest.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateRequest.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateRequest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateRequest.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,158 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.x500.X500Name; + +/** + * Parsing and encoding of a CertificateRequest struct from RFC 4346. + *
      + * struct {
      + *     ClientCertificateType certificate_types<1..2^8-1>;
      + *     DistinguishedName certificate_authorities<3..2^16-1>;
      + * } CertificateRequest;
      + * 
      + * + * @see ClientCertificateType + * @see X500Name + */ +public class CertificateRequest +{ + protected short[] certificateTypes; + protected Vector supportedSignatureAlgorithms; + protected Vector certificateAuthorities; + + /** + * @param certificateTypes see {@link ClientCertificateType} for valid constants. + * @param certificateAuthorities a {@link Vector} of {@link X500Name}. + */ + public CertificateRequest(short[] certificateTypes, Vector supportedSignatureAlgorithms, Vector certificateAuthorities) + { + this.certificateTypes = certificateTypes; + this.supportedSignatureAlgorithms = supportedSignatureAlgorithms; + this.certificateAuthorities = certificateAuthorities; + } + + /** + * @return an array of certificate types + * @see ClientCertificateType + */ + public short[] getCertificateTypes() + { + return certificateTypes; + } + + /** + * @return a {@link Vector} of {@link SignatureAndHashAlgorithm} (or null before TLS 1.2). + */ + public Vector getSupportedSignatureAlgorithms() + { + return supportedSignatureAlgorithms; + } + + /** + * @return a {@link Vector} of {@link X500Name} + */ + public Vector getCertificateAuthorities() + { + return certificateAuthorities; + } + + /** + * Encode this {@link CertificateRequest} to an {@link OutputStream}. + * + * @param output the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) + throws IOException + { + if (certificateTypes == null || certificateTypes.length == 0) + { + TlsUtils.writeUint8(0, output); + } + else + { + TlsUtils.writeUint8ArrayWithUint8Length(certificateTypes, output); + } + + if (supportedSignatureAlgorithms != null) + { + // TODO Check whether SignatureAlgorithm.anonymous is allowed here + TlsUtils.encodeSupportedSignatureAlgorithms(supportedSignatureAlgorithms, false, output); + } + + if (certificateAuthorities == null || certificateAuthorities.isEmpty()) + { + TlsUtils.writeUint16(0, output); + } + else + { + Vector derEncodings = new Vector(certificateAuthorities.size()); + + int totalLength = 0; + for (int i = 0; i < certificateAuthorities.size(); ++i) + { + X500Name certificateAuthority = (X500Name)certificateAuthorities.elementAt(i); + byte[] derEncoding = certificateAuthority.getEncoded(ASN1Encoding.DER); + derEncodings.addElement(derEncoding); + totalLength += derEncoding.length + 2; + } + + TlsUtils.checkUint16(totalLength); + TlsUtils.writeUint16(totalLength, output); + + for (int i = 0; i < derEncodings.size(); ++i) + { + byte[] derEncoding = (byte[])derEncodings.elementAt(i); + TlsUtils.writeOpaque16(derEncoding, output); + } + } + } + + /** + * Parse a {@link CertificateRequest} from an {@link InputStream}. + * + * @param context + * the {@link TlsContext} of the current connection. + * @param input + * the {@link InputStream} to parse from. + * @return a {@link CertificateRequest} object. + * @throws IOException + */ + public static CertificateRequest parse(TlsContext context, InputStream input) + throws IOException + { + int numTypes = TlsUtils.readUint8(input); + short[] certificateTypes = new short[numTypes]; + for (int i = 0; i < numTypes; ++i) + { + certificateTypes[i] = TlsUtils.readUint8(input); + } + + Vector supportedSignatureAlgorithms = null; + if (TlsUtils.isTLSv12(context)) + { + // TODO Check whether SignatureAlgorithm.anonymous is allowed here + supportedSignatureAlgorithms = TlsUtils.parseSupportedSignatureAlgorithms(false, input); + } + + Vector certificateAuthorities = new Vector(); + byte[] certAuthData = TlsUtils.readOpaque16(input); + ByteArrayInputStream bis = new ByteArrayInputStream(certAuthData); + while (bis.available() > 0) + { + byte[] derEncoding = TlsUtils.readOpaque16(bis); + ASN1Primitive asn1 = TlsUtils.readDERObject(derEncoding); + certificateAuthorities.addElement(X500Name.getInstance(asn1)); + } + + return new CertificateRequest(certificateTypes, supportedSignatureAlgorithms, certificateAuthorities); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateStatus.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateStatus.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateStatus.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateStatus.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,105 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ocsp.OCSPResponse; + +public class CertificateStatus +{ + protected short statusType; + protected Object response; + + public CertificateStatus(short statusType, Object response) + { + if (!isCorrectType(statusType, response)) + { + throw new IllegalArgumentException("'response' is not an instance of the correct type"); + } + + this.statusType = statusType; + this.response = response; + } + + public short getStatusType() + { + return statusType; + } + + public Object getResponse() + { + return response; + } + + public OCSPResponse getOCSPResponse() + { + if (!isCorrectType(CertificateStatusType.ocsp, response)) + { + throw new IllegalStateException("'response' is not an OCSPResponse"); + } + return (OCSPResponse)response; + } + + /** + * Encode this {@link CertificateStatus} to an {@link OutputStream}. + * + * @param output + * the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) throws IOException + { + TlsUtils.writeUint8(statusType, output); + + switch (statusType) + { + case CertificateStatusType.ocsp: + byte[] derEncoding = ((OCSPResponse) response).getEncoded(ASN1Encoding.DER); + TlsUtils.writeOpaque24(derEncoding, output); + break; + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + /** + * Parse a {@link CertificateStatus} from an {@link InputStream}. + * + * @param input + * the {@link InputStream} to parse from. + * @return a {@link CertificateStatus} object. + * @throws IOException + */ + public static CertificateStatus parse(InputStream input) throws IOException + { + short status_type = TlsUtils.readUint8(input); + Object response; + + switch (status_type) + { + case CertificateStatusType.ocsp: + { + byte[] derEncoding = TlsUtils.readOpaque24(input); + response = OCSPResponse.getInstance(TlsUtils.readDERObject(derEncoding)); + break; + } + default: + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + return new CertificateStatus(status_type, response); + } + + protected static boolean isCorrectType(short statusType, Object response) + { + switch (statusType) + { + case CertificateStatusType.ocsp: + return response instanceof OCSPResponse; + default: + throw new IllegalArgumentException("'statusType' is an unsupported value"); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateStatusRequest.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateStatusRequest.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateStatusRequest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateStatusRequest.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,98 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class CertificateStatusRequest +{ + protected short statusType; + protected Object request; + + public CertificateStatusRequest(short statusType, Object request) + { + if (!isCorrectType(statusType, request)) + { + throw new IllegalArgumentException("'request' is not an instance of the correct type"); + } + + this.statusType = statusType; + this.request = request; + } + + public short getStatusType() + { + return statusType; + } + + public Object getRequest() + { + return request; + } + + public OCSPStatusRequest getOCSPStatusRequest() + { + if (!isCorrectType(CertificateStatusType.ocsp, request)) + { + throw new IllegalStateException("'request' is not an OCSPStatusRequest"); + } + return (OCSPStatusRequest)request; + } + + /** + * Encode this {@link CertificateStatusRequest} to an {@link OutputStream}. + * + * @param output + * the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) throws IOException + { + TlsUtils.writeUint8(statusType, output); + + switch (statusType) + { + case CertificateStatusType.ocsp: + ((OCSPStatusRequest) request).encode(output); + break; + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + /** + * Parse a {@link CertificateStatusRequest} from an {@link InputStream}. + * + * @param input + * the {@link InputStream} to parse from. + * @return a {@link CertificateStatusRequest} object. + * @throws IOException + */ + public static CertificateStatusRequest parse(InputStream input) throws IOException + { + short status_type = TlsUtils.readUint8(input); + Object result; + + switch (status_type) + { + case CertificateStatusType.ocsp: + result = OCSPStatusRequest.parse(input); + break; + default: + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + return new CertificateStatusRequest(status_type, result); + } + + protected static boolean isCorrectType(short statusType, Object request) + { + switch (statusType) + { + case CertificateStatusType.ocsp: + return request instanceof OCSPStatusRequest; + default: + throw new IllegalArgumentException("'statusType' is an unsupported value"); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateStatusType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateStatusType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateStatusType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateStatusType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,9 @@ +package org.bouncycastle.tls; + +public class CertificateStatusType +{ + /* + * RFC 3546 3.6 + */ + public static final short ocsp = 1; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,15 @@ +package org.bouncycastle.tls; + +/** + * RFC 6091 + */ +public class CertificateType +{ + public static final short X509 = 0; + public static final short OpenPGP = 1; + + /* + * RFC 7250 + */ + public static final short RawPublicKey = 2; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateURL.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateURL.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CertificateURL.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CertificateURL.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,133 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + +/* + * RFC 3546 3.3 + */ +public class CertificateURL +{ + protected short type; + protected Vector urlAndHashList; + + /** + * @param type + * see {@link CertChainType} for valid constants. + * @param urlAndHashList + * a {@link Vector} of {@link URLAndHash}. + */ + public CertificateURL(short type, Vector urlAndHashList) + { + if (!CertChainType.isValid(type)) + { + throw new IllegalArgumentException("'type' is not a valid CertChainType value"); + } + if (urlAndHashList == null || urlAndHashList.isEmpty()) + { + throw new IllegalArgumentException("'urlAndHashList' must have length > 0"); + } + + this.type = type; + this.urlAndHashList = urlAndHashList; + } + + /** + * @return {@link CertChainType} + */ + public short getType() + { + return type; + } + + /** + * @return a {@link Vector} of {@link URLAndHash} + */ + public Vector getURLAndHashList() + { + return urlAndHashList; + } + + /** + * Encode this {@link CertificateURL} to an {@link OutputStream}. + * + * @param output the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) + throws IOException + { + TlsUtils.writeUint8(this.type, output); + + ListBuffer16 buf = new ListBuffer16(); + for (int i = 0; i < this.urlAndHashList.size(); ++i) + { + URLAndHash urlAndHash = (URLAndHash)this.urlAndHashList.elementAt(i); + urlAndHash.encode(buf); + } + buf.encodeTo(output); + } + + /** + * Parse a {@link CertificateURL} from an {@link InputStream}. + * + * @param context + * the {@link TlsContext} of the current connection. + * @param input + * the {@link InputStream} to parse from. + * @return a {@link CertificateURL} object. + * @throws IOException + */ + public static CertificateURL parse(TlsContext context, InputStream input) + throws IOException + { + short type = TlsUtils.readUint8(input); + if (!CertChainType.isValid(type)) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + int totalLength = TlsUtils.readUint16(input); + if (totalLength < 1) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + byte[] urlAndHashListData = TlsUtils.readFully(totalLength, input); + + ByteArrayInputStream buf = new ByteArrayInputStream(urlAndHashListData); + + Vector url_and_hash_list = new Vector(); + while (buf.available() > 0) + { + URLAndHash url_and_hash = URLAndHash.parse(context, buf); + url_and_hash_list.addElement(url_and_hash); + } + + return new CertificateURL(type, url_and_hash_list); + } + + // TODO Could be more generally useful + class ListBuffer16 extends ByteArrayOutputStream + { + ListBuffer16() throws IOException + { + // Reserve space for length + TlsUtils.writeUint16(0, this); + } + + void encodeTo(OutputStream output) throws IOException + { + // Patch actual length back in + int length = count - 2; + TlsUtils.checkUint16(length); + TlsUtils.writeUint16(length, buf, 0); + output.write(buf, 0, count); + buf = null; + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ChangeCipherSpec.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ChangeCipherSpec.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ChangeCipherSpec.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ChangeCipherSpec.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,6 @@ +package org.bouncycastle.tls; + +public class ChangeCipherSpec +{ + public static final short change_cipher_spec = 1; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java 2016-07-21 03:43:53.000000000 +0000 @@ -0,0 +1,387 @@ +package org.bouncycastle.tls; + +/** + * RFC 2246 A.5 + */ +public class CipherSuite +{ + public static final int TLS_NULL_WITH_NULL_NULL = 0x0000; + public static final int TLS_RSA_WITH_NULL_MD5 = 0x0001; + public static final int TLS_RSA_WITH_NULL_SHA = 0x0002; + public static final int TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003; + public static final int TLS_RSA_WITH_RC4_128_MD5 = 0x0004; + public static final int TLS_RSA_WITH_RC4_128_SHA = 0x0005; + public static final int TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x0006; + public static final int TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007; + public static final int TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008; + public static final int TLS_RSA_WITH_DES_CBC_SHA = 0x0009; + public static final int TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A; + public static final int TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B; + public static final int TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C; + public static final int TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D; + public static final int TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E; + public static final int TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F; + public static final int TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010; + public static final int TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011; + public static final int TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012; + public static final int TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013; + public static final int TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014; + public static final int TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x0015; + public static final int TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016; + public static final int TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017; + public static final int TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018; + public static final int TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x0019; + public static final int TLS_DH_anon_WITH_DES_CBC_SHA = 0x001A; + public static final int TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001B; + + /* + * Note: The cipher suite values { 0x00, 0x1C } and { 0x00, 0x1D } are reserved to avoid + * collision with Fortezza-based cipher suites in SSL 3. + */ + + /* + * RFC 3268 + */ + public static final int TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F; + public static final int TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030; + public static final int TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031; + public static final int TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032; + public static final int TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033; + public static final int TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x0034; + public static final int TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035; + public static final int TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036; + public static final int TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037; + public static final int TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038; + public static final int TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039; + public static final int TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003A; + + /* + * RFC 5932 + */ + public static final int TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041; + public static final int TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0042; + public static final int TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0043; + public static final int TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044; + public static final int TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045; + public static final int TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = 0x0046; + + public static final int TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0084; + public static final int TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085; + public static final int TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086; + public static final int TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087; + public static final int TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088; + public static final int TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089; + + public static final int TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BA; + public static final int TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BB; + public static final int TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BC; + public static final int TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BD; + public static final int TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BE; + public static final int TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BF; + + public static final int TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C0; + public static final int TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C1; + public static final int TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C2; + public static final int TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C3; + public static final int TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C4; + public static final int TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C5; + + /* + * RFC 4162 + */ + public static final int TLS_RSA_WITH_SEED_CBC_SHA = 0x0096; + public static final int TLS_DH_DSS_WITH_SEED_CBC_SHA = 0x0097; + public static final int TLS_DH_RSA_WITH_SEED_CBC_SHA = 0x0098; + public static final int TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099; + public static final int TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A; + public static final int TLS_DH_anon_WITH_SEED_CBC_SHA = 0x009B; + + /* + * RFC 4279 + */ + public static final int TLS_PSK_WITH_RC4_128_SHA = 0x008A; + public static final int TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B; + public static final int TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C; + public static final int TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D; + public static final int TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E; + public static final int TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F; + public static final int TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090; + public static final int TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091; + public static final int TLS_RSA_PSK_WITH_RC4_128_SHA = 0x0092; + public static final int TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = 0x0093; + public static final int TLS_RSA_PSK_WITH_AES_128_CBC_SHA = 0x0094; + public static final int TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095; + + /* + * RFC 4492 + */ + public static final int TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001; + public static final int TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002; + public static final int TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003; + public static final int TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0xC004; + public static final int TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005; + public static final int TLS_ECDHE_ECDSA_WITH_NULL_SHA = 0xC006; + public static final int TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007; + public static final int TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008; + public static final int TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009; + public static final int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A; + public static final int TLS_ECDH_RSA_WITH_NULL_SHA = 0xC00B; + public static final int TLS_ECDH_RSA_WITH_RC4_128_SHA = 0xC00C; + public static final int TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = 0xC00D; + public static final int TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = 0xC00E; + public static final int TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = 0xC00F; + public static final int TLS_ECDHE_RSA_WITH_NULL_SHA = 0xC010; + public static final int TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011; + public static final int TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012; + public static final int TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013; + public static final int TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014; + public static final int TLS_ECDH_anon_WITH_NULL_SHA = 0xC015; + public static final int TLS_ECDH_anon_WITH_RC4_128_SHA = 0xC016; + public static final int TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = 0xC017; + public static final int TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018; + public static final int TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019; + + /* + * RFC 4785 + */ + public static final int TLS_PSK_WITH_NULL_SHA = 0x002C; + public static final int TLS_DHE_PSK_WITH_NULL_SHA = 0x002D; + public static final int TLS_RSA_PSK_WITH_NULL_SHA = 0x002E; + + /* + * RFC 5054 + */ + public static final int TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A; + public static final int TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01B; + public static final int TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01C; + public static final int TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D; + public static final int TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01E; + public static final int TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01F; + public static final int TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020; + public static final int TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021; + public static final int TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022; + + /* + * RFC 5246 + */ + public static final int TLS_RSA_WITH_NULL_SHA256 = 0x003B; + public static final int TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C; + public static final int TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D; + public static final int TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x003E; + public static final int TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x003F; + public static final int TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040; + public static final int TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067; + public static final int TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x0068; + public static final int TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x0069; + public static final int TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A; + public static final int TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B; + public static final int TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x006C; + public static final int TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x006D; + + /* + * RFC 5288 + */ + public static final int TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C; + public static final int TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D; + public static final int TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E; + public static final int TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F; + public static final int TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = 0x00A0; + public static final int TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = 0x00A1; + public static final int TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2; + public static final int TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3; + public static final int TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = 0x00A4; + public static final int TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = 0x00A5; + public static final int TLS_DH_anon_WITH_AES_128_GCM_SHA256 = 0x00A6; + public static final int TLS_DH_anon_WITH_AES_256_GCM_SHA384 = 0x00A7; + + /* + * RFC 5289 + */ + public static final int TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023; + public static final int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024; + public static final int TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC025; + public static final int TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC026; + public static final int TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027; + public static final int TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028; + public static final int TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = 0xC029; + public static final int TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = 0xC02A; + public static final int TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B; + public static final int TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C; + public static final int TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02D; + public static final int TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02E; + public static final int TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F; + public static final int TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030; + public static final int TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031; + public static final int TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032; + + /* + * RFC 5487 + */ + public static final int TLS_PSK_WITH_AES_128_GCM_SHA256 = 0x00A8; + public static final int TLS_PSK_WITH_AES_256_GCM_SHA384 = 0x00A9; + public static final int TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = 0x00AA; + public static final int TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = 0x00AB; + public static final int TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = 0x00AC; + public static final int TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = 0x00AD; + public static final int TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE; + public static final int TLS_PSK_WITH_AES_256_CBC_SHA384 = 0x00AF; + public static final int TLS_PSK_WITH_NULL_SHA256 = 0x00B0; + public static final int TLS_PSK_WITH_NULL_SHA384 = 0x00B1; + public static final int TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = 0x00B2; + public static final int TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = 0x00B3; + public static final int TLS_DHE_PSK_WITH_NULL_SHA256 = 0x00B4; + public static final int TLS_DHE_PSK_WITH_NULL_SHA384 = 0x00B5; + public static final int TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = 0x00B6; + public static final int TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = 0x00B7; + public static final int TLS_RSA_PSK_WITH_NULL_SHA256 = 0x00B8; + public static final int TLS_RSA_PSK_WITH_NULL_SHA384 = 0x00B9; + + /* + * RFC 5489 + */ + public static final int TLS_ECDHE_PSK_WITH_RC4_128_SHA = 0xC033; + public static final int TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = 0xC034; + public static final int TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = 0xC035; + public static final int TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = 0xC036; + public static final int TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = 0xC037; + public static final int TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = 0xC038; + public static final int TLS_ECDHE_PSK_WITH_NULL_SHA = 0xC039; + public static final int TLS_ECDHE_PSK_WITH_NULL_SHA256 = 0xC03A; + public static final int TLS_ECDHE_PSK_WITH_NULL_SHA384 = 0xC03B; + + /* + * RFC 5746 + */ + public static final int TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF; + + /* + * RFC 6367 + */ + public static final int TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC072; + public static final int TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC073; + public static final int TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC074; + public static final int TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC075; + public static final int TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC076; + public static final int TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC077; + public static final int TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC078; + public static final int TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC079; + + public static final int TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07A; + public static final int TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07B; + public static final int TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07C; + public static final int TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07D; + public static final int TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07E; + public static final int TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07F; + public static final int TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC080; + public static final int TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC081; + public static final int TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC082; + public static final int TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC083; + public static final int TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 = 0xC084; + public static final int TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 = 0xC085; + public static final int TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC086; + public static final int TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC087; + public static final int TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC088; + public static final int TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC089; + public static final int TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08A; + public static final int TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08B; + public static final int TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08C; + public static final int TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08D; + + public static final int TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08E; + public static final int TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08F; + public static final int TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC090; + public static final int TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC091; + public static final int TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC092; + public static final int TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC093; + public static final int TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC094; + public static final int TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC095; + public static final int TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC096; + public static final int TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC097; + public static final int TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC098; + public static final int TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC099; + public static final int TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC09A; + public static final int TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC09B; + + /* + * RFC 6655 + */ + public static final int TLS_RSA_WITH_AES_128_CCM = 0xC09C; + public static final int TLS_RSA_WITH_AES_256_CCM = 0xC09D; + public static final int TLS_DHE_RSA_WITH_AES_128_CCM = 0xC09E; + public static final int TLS_DHE_RSA_WITH_AES_256_CCM = 0xC09F; + public static final int TLS_RSA_WITH_AES_128_CCM_8 = 0xC0A0; + public static final int TLS_RSA_WITH_AES_256_CCM_8 = 0xC0A1; + public static final int TLS_DHE_RSA_WITH_AES_128_CCM_8 = 0xC0A2; + public static final int TLS_DHE_RSA_WITH_AES_256_CCM_8 = 0xC0A3; + public static final int TLS_PSK_WITH_AES_128_CCM = 0xC0A4; + public static final int TLS_PSK_WITH_AES_256_CCM = 0xC0A5; + public static final int TLS_DHE_PSK_WITH_AES_128_CCM = 0xC0A6; + public static final int TLS_DHE_PSK_WITH_AES_256_CCM = 0xC0A7; + public static final int TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8; + public static final int TLS_PSK_WITH_AES_256_CCM_8 = 0xC0A9; + public static final int TLS_PSK_DHE_WITH_AES_128_CCM_8 = 0xC0AA; + public static final int TLS_PSK_DHE_WITH_AES_256_CCM_8 = 0xC0AB; + + /* + * RFC 7251 + */ + public static final int TLS_ECDHE_ECDSA_WITH_AES_128_CCM = 0xC0AC; + public static final int TLS_ECDHE_ECDSA_WITH_AES_256_CCM = 0xC0AD; + public static final int TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE; + public static final int TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = 0xC0AF; + + /* + * RFC 7507 + */ + public static final int TLS_FALLBACK_SCSV = 0x5600; + + /* + * RFC 7905 + */ + public static final int TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8; + public static final int TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9; + public static final int TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAA; + public static final int TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAB; + public static final int TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAC; + public static final int TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAD; + public static final int TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAE; + + /* + * draft-zauner-tls-aes-ocb-04 (code points TBD) + */ + public static final int DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB = 0xFF00; + public static final int DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB = 0xFF01; + public static final int DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB = 0xFF02; + public static final int DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB = 0xFF03; + public static final int DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB = 0xFF04; + public static final int DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB = 0xFF05; + public static final int DRAFT_TLS_PSK_WITH_AES_128_OCB = 0xFF10; + public static final int DRAFT_TLS_PSK_WITH_AES_256_OCB = 0xFF11; + public static final int DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB = 0xFF12; + public static final int DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB = 0xFF13; + public static final int DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB = 0xFF14; + public static final int DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB = 0xFF15; + + /* + * draft-ietf-tls-ecdhe-psk-aead-00 (code points TBD) + */ + public static final int DRAFT_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 = 0xFE00; + public static final int DRAFT_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 = 0xFE01; + public static final int DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256 = 0xFE02; + // TODO[draft-ietf-tls-ecdhe-psk-aead-00] Possibly should be ..._SHA384 + public static final int DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_8_SHA256 = 0xFE03; + public static final int DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256 = 0xFE04; + public static final int DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_SHA384 = 0xFE05; + + public static boolean isSCSV(int cipherSuite) + { + switch (cipherSuite) + { + case TLS_EMPTY_RENEGOTIATION_INFO_SCSV: + case TLS_FALLBACK_SCSV: + return true; + default: + return false; + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CipherType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CipherType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CipherType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CipherType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,18 @@ +package org.bouncycastle.tls; + +/** + * RFC 2246 + *

      + * Note that the values here are implementation-specific and arbitrary. It is recommended not to + * depend on the particular values (e.g. serialization). + */ +public class CipherType +{ + public static final int stream = 0; + public static final int block = 1; + + /* + * RFC 5246 + */ + public static final int aead = 2; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ClientAuthenticationType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ClientAuthenticationType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ClientAuthenticationType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ClientAuthenticationType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,11 @@ +package org.bouncycastle.tls; + +public class ClientAuthenticationType +{ + /* + * RFC 5077 4 + */ + public static final short anonymous = 0; + public static final short certificate_based = 1; + public static final short psk = 2; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ClientCertificateType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ClientCertificateType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ClientCertificateType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ClientCertificateType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,22 @@ +package org.bouncycastle.tls; + +public class ClientCertificateType +{ + /* + * RFC 4346 7.4.4 + */ + public static final short rsa_sign = 1; + public static final short dss_sign = 2; + public static final short rsa_fixed_dh = 3; + public static final short dss_fixed_dh = 4; + public static final short rsa_ephemeral_dh_RESERVED = 5; + public static final short dss_ephemeral_dh_RESERVED = 6; + public static final short fortezza_dms_RESERVED = 20; + + /* + * RFC 4492 5.5 + */ + public static final short ecdsa_sign = 64; + public static final short rsa_fixed_ecdh = 65; + public static final short ecdsa_fixed_ecdh = 66; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CombinedHash.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CombinedHash.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CombinedHash.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CombinedHash.java 2016-10-09 23:54:32.000000000 +0000 @@ -0,0 +1,112 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsHash; +import org.bouncycastle.util.Arrays; + +/** + * A combined hash, which implements md5(m) || sha1(m). + */ +public class CombinedHash + implements TlsHandshakeHash +{ + protected TlsContext context; + protected TlsCrypto crypto; + protected TlsHash md5; + protected TlsHash sha1; + + public CombinedHash(TlsContext context) + { + this(context.getCrypto()); + this.context = context; + } + + public CombinedHash(TlsCrypto crypto) + { + this.crypto = crypto; + this.md5 = crypto.createHash(HashAlgorithm.md5); + this.sha1 = crypto.createHash(HashAlgorithm.sha1); + } + + public CombinedHash(CombinedHash t) + { + this.context = t.context; + this.crypto = t.crypto; + this.md5 = (TlsHash)t.md5.clone(); + this.sha1 = (TlsHash)t.sha1.clone(); + } + + public TlsHandshakeHash notifyPRFDetermined() + { + return this; + } + + public void trackHashAlgorithm(short hashAlgorithm) + { + throw new IllegalStateException("CombinedHash only supports calculating the legacy PRF for handshake hash"); + } + + public void sealHashAlgorithms() + { + } + + public TlsHandshakeHash stopTracking() + { + return new CombinedHash(this); + } + + public TlsHash forkPRFHash() + { + return new CombinedHash(this); + } + + public byte[] getFinalHash(short hashAlgorithm) + { + throw new IllegalStateException("CombinedHash doesn't support multiple hashes"); + } + + public void update(byte[] input, int inOff, int len) + { + md5.update(input, inOff, len); + sha1.update(input, inOff, len); + } + + public byte[] calculateHash() + { + if (context != null && TlsUtils.isSSL(context)) + { + byte[] ipad = SSL3Constants.getInputPad(); + byte[] opad = SSL3Constants.getOutputPad(); + + ssl3Complete(md5, ipad, opad, 48); + ssl3Complete(sha1, ipad, opad, 40); + } + + return Arrays.concatenate(md5.calculateHash(), sha1.calculateHash()); + } + + public Object clone() + { + return new CombinedHash(this); + } + + public void reset() + { + md5.reset(); + sha1.reset(); + } + + protected void ssl3Complete(TlsHash d, byte[] ipad, byte[] opad, int padLength) + { + byte[] master_secret = crypto.adoptSecret(context.getSecurityParameters().getMasterSecret()).extract(); + + d.update(master_secret, 0, master_secret.length); + d.update(ipad, 0, padLength); + + byte[] tmp = d.calculateHash(); + + d.update(master_secret, 0, master_secret.length); + d.update(opad, 0, padLength); + d.update(tmp, 0, tmp.length); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CompressionMethod.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CompressionMethod.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/CompressionMethod.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/CompressionMethod.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,19 @@ +package org.bouncycastle.tls; + +/** + * RFC 2246 6.1 + */ +public class CompressionMethod +{ + public static final short _null = 0; + + /* + * RFC 3749 2 + */ + public static final short DEFLATE = 1; + + /* + * Values from 224 decimal (0xE0) through 255 decimal (0xFF) + * inclusive are reserved for private use. + */ +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ConnectionEnd.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ConnectionEnd.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ConnectionEnd.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ConnectionEnd.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,13 @@ +package org.bouncycastle.tls; + +/** + * RFC 2246 + *

      + * Note that the values here are implementation-specific and arbitrary. It is recommended not to + * depend on the particular values (e.g. serialization). + */ +public class ConnectionEnd +{ + public static final int server = 0; + public static final int client = 1; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ContentType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ContentType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ContentType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ContentType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,13 @@ +package org.bouncycastle.tls; + +/** + * RFC 2246 6.2.1 + */ +public class ContentType +{ + public static final short change_cipher_spec = 20; + public static final short alert = 21; + public static final short handshake = 22; + public static final short application_data = 23; + public static final short heartbeat = 24; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/DHGroup.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/DHGroup.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/DHGroup.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/DHGroup.java 2016-10-03 01:46:45.000000000 +0000 @@ -0,0 +1,53 @@ +package org.bouncycastle.tls.crypto; + +import java.math.BigInteger; + +/** + * Carrier class for Diffie-Hellman group parameters. + */ +public class DHGroup +{ + private final BigInteger p; + private final BigInteger q; + private final BigInteger g; + + /** + * Base constructor. + * + * @param p the prime modulus. + * @param g the base generator. + */ + public DHGroup(BigInteger p, BigInteger g) + { + this(p, null, g); + } + + /** + * Base constructor with the prime factor of (p - 1). + * + * @param p the prime modulus. + * @param q specifies the prime factor of (p - 1). + * @param g the base generator. + */ + public DHGroup(BigInteger p, BigInteger q, BigInteger g) + { + this.p = p; + this.g = g; + this.q = q; + } + + public BigInteger getG() + { + return g; + } + + public BigInteger getP() + { + return p; + } + + public BigInteger getQ() + { + return q; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/DHStandardGroups.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/DHStandardGroups.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/DHStandardGroups.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/DHStandardGroups.java 2016-10-25 05:52:36.000000000 +0000 @@ -0,0 +1,152 @@ +package org.bouncycastle.tls.crypto; + +import java.math.BigInteger; + +import org.bouncycastle.util.encoders.Hex; + +/** + * Standard Diffie-Hellman groups from various IETF specifications. + */ +public class DHStandardGroups +{ + private static BigInteger fromHex(String hex) + { + return new BigInteger(1, Hex.decode(hex)); + } + + private static DHGroup fromPG(String hexP, String hexG) + { + return new DHGroup(fromHex(hexP), fromHex(hexG)); + } + + /* + * RFC 2409 + */ + private static final String rfc2409_768_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"; + private static final String rfc2409_768_g = "02"; + public static final DHGroup rfc2409_768 = fromPG(rfc2409_768_p, rfc2409_768_g); + + private static final String rfc2409_1024_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + + "FFFFFFFFFFFFFFFF"; + private static final String rfc2409_1024_g = "02"; + public static final DHGroup rfc2409_1024 = fromPG(rfc2409_1024_p, rfc2409_1024_g); + + /* + * RFC 3526 + */ + private static final String rfc3526_1536_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"; + private static final String rfc3526_1536_g = "02"; + public static final DHGroup rfc3526_1536 = fromPG(rfc3526_1536_p, rfc3526_1536_g); + + private static final String rfc3526_2048_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AACAA68FFFFFFFFFFFFFFFF"; + private static final String rfc3526_2048_g = "02"; + public static final DHGroup rfc3526_2048 = fromPG(rfc3526_2048_p, rfc3526_2048_g); + + private static final String rfc3526_3072_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"; + private static final String rfc3526_3072_g = "02"; + public static final DHGroup rfc3526_3072 = fromPG(rfc3526_3072_p, rfc3526_3072_g); + + private static final String rfc3526_4096_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + + "FFFFFFFFFFFFFFFF"; + private static final String rfc3526_4096_g = "02"; + public static final DHGroup rfc3526_4096 = fromPG(rfc3526_4096_p, rfc3526_4096_g); + + private static final String rfc3526_6144_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + + "6DCC4024FFFFFFFFFFFFFFFF"; + private static final String rfc3526_6144_g = "02"; + public static final DHGroup rfc3526_6144 = fromPG(rfc3526_6144_p, rfc3526_6144_g); + + private static final String rfc3526_8192_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" + "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" + + "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" + + "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" + "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" + + "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" + + "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" + "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" + + "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" + "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" + + "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" + "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" + + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" + "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" + + "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" + "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" + + "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" + "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" + + "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF"; + private static final String rfc3526_8192_g = "02"; + public static final DHGroup rfc3526_8192 = fromPG(rfc3526_8192_p, rfc3526_8192_g); + + /* + * RFC 4306 + */ + public static final DHGroup rfc4306_768 = rfc2409_768; + public static final DHGroup rfc4306_1024 = rfc2409_1024; + + /* + * RFC 5996 + */ + public static final DHGroup rfc5996_768 = rfc4306_768; + public static final DHGroup rfc5996_1024 = rfc4306_1024; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/AbstractTlsCrypto.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/AbstractTlsCrypto.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/AbstractTlsCrypto.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/AbstractTlsCrypto.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,59 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +import org.bouncycastle.tls.EncryptionAlgorithm; +import org.bouncycastle.tls.MACAlgorithm; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsSecret; + +/** + * Base class for a TlsCrypto implementation that provides some needed methods from elsewhere in the impl package. + */ +public abstract class AbstractTlsCrypto + implements TlsCrypto +{ + /** + * Adopt the passed in secret, creating a new copy of it.. + * + * @param secret the secret to make a copy of. + * @return a TlsSecret based the original secret. + */ + public TlsSecret adoptSecret(TlsSecret secret) + { + if (secret instanceof AbstractTlsSecret) + { + AbstractTlsSecret sec = (AbstractTlsSecret)secret; + + return createSecret(sec.copyData()); + } + + throw new IllegalArgumentException("unrecognized TlsSecret - cannot copy data: " + secret.getClass().getName()); + } + + /** + * Create a cipher for the specified encryption and MAC algorithms. + *

      + * See enumeration classes {@link EncryptionAlgorithm}, {@link MACAlgorithm} for appropriate argument values. + *

      + * @param cryptoParams context specific parameters. + * @param encryptionAlgorithm the encryption algorithm to be employed by the cipher. + * @param macAlgorithm the MAC algorithm to be employed by the cipher. + * @return a {@link TlsCipher} implementing the encryption and MAC algorithm. + * @throws IOException + */ + protected abstract TlsCipher createCipher(TlsCryptoParameters cryptoParams, int encryptionAlgorithm, int macAlgorithm) + throws IOException; + + /** + * Return an encryptor based on the public key in certificate. + * + * @param certificate the certificate carrying the public key. + * @return a TlsEncryptor based on the certificate's public key. + */ + protected abstract TlsEncryptor createEncryptor(TlsCertificate certificate) + throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/AbstractTlsSecret.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/AbstractTlsSecret.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/AbstractTlsSecret.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/AbstractTlsSecret.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,93 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.Arrays; + +/** + * Base class for a TlsSecret implementation which captures common code and fields. + */ +public abstract class AbstractTlsSecret + implements TlsSecret +{ + protected static final int MD5_SIZE = 16; + + // SSL3 magic mix constants ("A", "BB", "CCC", ...) + protected static final byte[][] SSL3_CONST = generateSSL3Constants(); + + private static byte[][] generateSSL3Constants() + { + int n = 10; + byte[][] arr = new byte[n][]; + for (int i = 0; i < n; i++) + { + byte[] b = new byte[i + 1]; + Arrays.fill(b, (byte)('A' + i)); + arr[i] = b; + } + return arr; + } + + protected byte[] data; + + /** + * Base constructor. + * + * @param data the byte[] making up the secret value. + */ + protected AbstractTlsSecret(byte[] data) + { + this.data = data; + } + + public synchronized byte[] encrypt(TlsCertificate certificate) throws IOException + { + checkAlive(); + + return getCrypto().createEncryptor(certificate).encrypt(data, 0, data.length); + } + + public synchronized void destroy() + { + if (data != null) + { + // TODO Is there a way to ensure the data is really overwritten? + Arrays.fill(data, (byte)0); + this.data = null; + } + } + + public synchronized byte[] extract() + { + checkAlive(); + + byte[] result = data; + this.data = null; + return result; + } + + public TlsCipher createCipher(TlsCryptoParameters contextParams, int encryptionAlgorithm, int macAlgorithm) + throws IOException + { + return getCrypto().createCipher(contextParams, encryptionAlgorithm, macAlgorithm); + } + + byte[] copyData() + { + return Arrays.clone(data); + } + + protected void checkAlive() + { + if (data == null) + { + throw new IllegalStateException("Secret has already been extracted or destroyed"); + } + } + + protected abstract AbstractTlsCrypto getCrypto(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.java 2016-11-05 03:46:32.000000000 +0000 @@ -0,0 +1,138 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import java.io.IOException; +import java.math.BigInteger; + +import org.bouncycastle.crypto.BasicAgreement; +import org.bouncycastle.crypto.agreement.DHBasicAgreement; +import org.bouncycastle.crypto.agreement.ECDHBasicAgreement; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.DHPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.TlsCredentialedAgreement; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.BigIntegers; + +/** + * Credentialed class generating agreed secrets from a peer's public key for our end of the TLS connection using the BC light-weight API. + */ +public class BcDefaultTlsCredentialedAgreement + implements TlsCredentialedAgreement +{ + protected TlsCredentialedAgreement agreementCredentials; + + public BcDefaultTlsCredentialedAgreement(BcTlsCrypto crypto, Certificate certificate, AsymmetricKeyParameter privateKey) + { + if (crypto == null) + { + throw new IllegalArgumentException("'crypto' cannot be null"); + } + if (certificate == null) + { + throw new IllegalArgumentException("'certificate' cannot be null"); + } + if (certificate.isEmpty()) + { + throw new IllegalArgumentException("'certificate' cannot be empty"); + } + if (privateKey == null) + { + throw new IllegalArgumentException("'privateKey' cannot be null"); + } + if (!privateKey.isPrivate()) + { + throw new IllegalArgumentException("'privateKey' must be private"); + } + + if (privateKey instanceof DHPrivateKeyParameters) + { + agreementCredentials = new DHCredentialedAgreement(crypto, privateKey, certificate); + } + else if (privateKey instanceof ECPrivateKeyParameters) + { + agreementCredentials = new ECCredentialedAgreement(crypto, privateKey, certificate); + } + else + { + throw new IllegalArgumentException("'privateKey' type not supported: " + + privateKey.getClass().getName()); + } + } + + public Certificate getCertificate() + { + return agreementCredentials.getCertificate(); + } + + public TlsSecret generateAgreement(TlsCertificate peerCertificate) + throws IOException + { + return agreementCredentials.generateAgreement(peerCertificate); + } + + private class DHCredentialedAgreement + implements TlsCredentialedAgreement + { + private final Certificate certificate; + private final BcTlsCrypto crypto; + protected AsymmetricKeyParameter privateKey; + + protected BasicAgreement basicAgreement = new DHBasicAgreement(); + + public DHCredentialedAgreement(BcTlsCrypto crypto, AsymmetricKeyParameter privateKey, Certificate certificate) + { + this.crypto = crypto; + this.privateKey = privateKey; + this.certificate = certificate; + } + + public TlsSecret generateAgreement(TlsCertificate peerCertificate) + throws IOException + { + TlsCertificate localCert = certificate.getCertificateAt(0); + AsymmetricKeyParameter peerPublicKey = BcTlsCertificate.convert(crypto, localCert).getPublicKey(); + basicAgreement.init(privateKey); + BigInteger agreementValue = basicAgreement.calculateAgreement(peerPublicKey); + return crypto.adoptLocalSecret(BigIntegers.asUnsignedByteArray(agreementValue)); + } + + public Certificate getCertificate() + { + return certificate; + } + } + + private class ECCredentialedAgreement + implements TlsCredentialedAgreement + { + private final Certificate certificate; + private final BcTlsCrypto crypto; + private final AsymmetricKeyParameter privateKey; + + protected BasicAgreement basicAgreement = new ECDHBasicAgreement(); + + public ECCredentialedAgreement(BcTlsCrypto crypto, AsymmetricKeyParameter privateKey, Certificate certificate) + { + this.crypto = crypto; + this.privateKey = privateKey; + this.certificate = certificate; + } + + public TlsSecret generateAgreement(TlsCertificate peerCertificate) + throws IOException + { + TlsCertificate localCert = certificate.getCertificateAt(0); + AsymmetricKeyParameter peerPublicKey = BcTlsCertificate.convert(crypto, localCert).getPublicKey(); + basicAgreement.init(privateKey); + BigInteger agreementValue = basicAgreement.calculateAgreement(peerPublicKey); + return crypto.adoptLocalSecret(BigIntegers.asUnsignedByteArray(basicAgreement.getFieldSize(), agreementValue)); + } + + public Certificate getCertificate() + { + return certificate; + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java 2016-11-05 03:46:32.000000000 +0000 @@ -0,0 +1,160 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import java.io.IOException; +import java.security.SecureRandom; + +import org.bouncycastle.crypto.encodings.PKCS1Encoding; +import org.bouncycastle.crypto.engines.RSABlindedEngine; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.TlsCredentialedDecryptor; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.Arrays; + +/** + * Credentialed class decrypting RSA encrypted secrets sent from a peer for our end of the TLS connection using the BC light-weight API. + */ +public class BcDefaultTlsCredentialedDecryptor + implements TlsCredentialedDecryptor +{ + protected BcTlsCrypto crypto; + protected Certificate certificate; + protected AsymmetricKeyParameter privateKey; + + public BcDefaultTlsCredentialedDecryptor(BcTlsCrypto crypto, Certificate certificate, + AsymmetricKeyParameter privateKey) + { + if (crypto == null) + { + throw new IllegalArgumentException("'crypto' cannot be null"); + } + if (certificate == null) + { + throw new IllegalArgumentException("'certificate' cannot be null"); + } + if (certificate.isEmpty()) + { + throw new IllegalArgumentException("'certificate' cannot be empty"); + } + if (privateKey == null) + { + throw new IllegalArgumentException("'privateKey' cannot be null"); + } + if (!privateKey.isPrivate()) + { + throw new IllegalArgumentException("'privateKey' must be private"); + } + + if (privateKey instanceof RSAKeyParameters) + { + } + else + { + throw new IllegalArgumentException("'privateKey' type not supported: " + + privateKey.getClass().getName()); + } + + this.crypto = crypto; + this.certificate = certificate; + this.privateKey = privateKey; + } + + public Certificate getCertificate() + { + return certificate; + } + + public TlsSecret decrypt(TlsCryptoParameters cryptoParams, byte[] ciphertext) throws IOException + { + // TODO Keep only the decryption itself here - move error handling outside + return safeDecryptPreMasterSecret(cryptoParams, (RSAKeyParameters)privateKey, ciphertext); + } + + /* + * TODO[tls-ops] Probably need to make RSA encryption/decryption into TlsCrypto functions so + * that users can implement "generic" encryption credentials externally + */ + protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams, RSAKeyParameters rsaServerPrivateKey, + byte[] encryptedPreMasterSecret) + { + SecureRandom secureRandom = crypto.getSecureRandom(); + + /* + * RFC 5246 7.4.7.1. + */ + ProtocolVersion clientVersion = cryptoParams.getClientVersion(); + + // TODO Provide as configuration option? + boolean versionNumberCheckDisabled = false; + + /* + * Generate 48 random bytes we can use as a Pre-Master-Secret, if the + * PKCS1 padding check should fail. + */ + byte[] fallback = new byte[48]; + secureRandom.nextBytes(fallback); + + byte[] M = Arrays.clone(fallback); + try + { + PKCS1Encoding encoding = new PKCS1Encoding(new RSABlindedEngine(), fallback); + encoding.init(false, new ParametersWithRandom(rsaServerPrivateKey, secureRandom)); + + M = encoding.processBlock(encryptedPreMasterSecret, 0, encryptedPreMasterSecret.length); + } + catch (Exception e) + { + /* + * This should never happen since the decryption should never throw an exception + * and return a random value instead. + * + * In any case, a TLS server MUST NOT generate an alert if processing an + * RSA-encrypted premaster secret message fails, or the version number is not as + * expected. Instead, it MUST continue the handshake with a randomly generated + * premaster secret. + */ + } + + /* + * If ClientHello.client_version is TLS 1.1 or higher, server implementations MUST + * check the version number [..]. + */ + if (versionNumberCheckDisabled && clientVersion.isEqualOrEarlierVersionOf(ProtocolVersion.TLSv10)) + { + /* + * If the version number is TLS 1.0 or earlier, server + * implementations SHOULD check the version number, but MAY have a + * configuration option to disable the check. + * + * So there is nothing to do here. + */ + } + else + { + /* + * OK, we need to compare the version number in the decrypted Pre-Master-Secret with the + * clientVersion received during the handshake. If they don't match, we replace the + * decrypted Pre-Master-Secret with a random one. + */ + int correct = (clientVersion.getMajorVersion() ^ (M[0] & 0xff)) + | (clientVersion.getMinorVersion() ^ (M[1] & 0xff)); + correct |= correct >> 1; + correct |= correct >> 2; + correct |= correct >> 4; + int mask = ~((correct & 1) - 1); + + /* + * mask will be all bits set to 0xff if the version number differed. + */ + for (int i = 0; i < 48; i++) + { + M[i] = (byte)((M[i] & (~mask)) | (fallback[i] & mask)); + } + } + return crypto.createSecret(M); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.java 2016-11-05 03:46:32.000000000 +0000 @@ -0,0 +1,46 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.DefaultTlsCredentialedSigner; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsSigner; + +/** + * Credentialed class for generating signatures based on the use of primitives from the BC light-weight API. + */ +public class BcDefaultTlsCredentialedSigner + extends DefaultTlsCredentialedSigner +{ + private static TlsSigner makeSigner(BcTlsCrypto crypto, AsymmetricKeyParameter privateKey) + { + TlsSigner signer; + if (privateKey instanceof RSAKeyParameters) + { + signer = new BcTlsRSASigner(crypto, privateKey); + } + else if (privateKey instanceof DSAPrivateKeyParameters) + { + signer = new BcTlsDSASigner(crypto, privateKey); + } + else if (privateKey instanceof ECPrivateKeyParameters) + { + signer = new BcTlsECDSASigner(crypto, privateKey); + } + else + { + throw new IllegalArgumentException("'privateKey' type not supported: " + privateKey.getClass().getName()); + } + + return signer; + } + + public BcDefaultTlsCredentialedSigner(TlsCryptoParameters cryptoParams, BcTlsCrypto crypto, AsymmetricKeyParameter privateKey, Certificate certificate, SignatureAndHashAlgorithm signatureAndHashAlgorithm) + { + super(cryptoParams, makeSigner(crypto, privateKey), certificate, signatureAndHashAlgorithm); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCertificate.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCertificate.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCertificate.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCertificate.java 2016-11-21 10:28:25.000000000 +0000 @@ -0,0 +1,310 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.DHPublicKeyParameters; +import org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.crypto.util.PublicKeyFactory; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.ConnectionEnd; +import org.bouncycastle.tls.KeyExchangeAlgorithm; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.TlsDHUtils; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsVerifier; + +/** + * Implementation class for a single X.509 certificate based on the BC light-weight API. + */ +public class BcTlsCertificate + implements TlsCertificate +{ + public static BcTlsCertificate convert(BcTlsCrypto crypto, TlsCertificate certificate) + throws IOException + { + if (certificate instanceof BcTlsCertificate) + { + return (BcTlsCertificate)certificate; + } + + return new BcTlsCertificate(crypto, certificate.getEncoded()); + } + + private final BcTlsCrypto crypto; + + protected final Certificate certificate; + + protected DHPublicKeyParameters pubKeyDH = null; + protected ECPublicKeyParameters pubKeyEC = null; + protected RSAKeyParameters pubKeyRSA = null; + + public BcTlsCertificate(BcTlsCrypto crypto, byte[] encoding) + throws IOException + { + this.crypto = crypto; + try + { + this.certificate = Certificate.getInstance(encoding); + } + catch (IllegalArgumentException e) + { + throw new IOException("unable to decode certificate: " + e.getMessage(), e); + } + } + + public TlsVerifier createVerifier(short signatureAlgorithm) throws IOException + { + validateKeyUsage(KeyUsage.digitalSignature); + + switch (signatureAlgorithm) + { + case SignatureAlgorithm.dsa: + return new BcTlsDSAVerifier(this.crypto, getPubKeyDSS()); + + case SignatureAlgorithm.ecdsa: + return new BcTlsECDSAVerifier(this.crypto, getPubKeyEC()); + + case SignatureAlgorithm.rsa: + return new BcTlsRSAVerifier(getPubKeyRSA()); + + default: + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + } + + public short getClientCertificateType() throws IOException + { + AsymmetricKeyParameter publicKey = getPublicKey(); + if (publicKey.isPrivate()) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + try + { + /* + * TODO RFC 5246 7.4.6. The certificates MUST be signed using an acceptable hash/ + * signature algorithm pair, as described in Section 7.4.4. Note that this relaxes the + * constraints on certificate-signing algorithms found in prior versions of TLS. + */ + + /* + * RFC 5246 7.4.6. Client Certificate + */ + + /* + * RSA public key; the certificate MUST allow the key to be used for signing with the + * signature scheme and hash algorithm that will be employed in the certificate verify + * message. + */ + if (publicKey instanceof RSAKeyParameters) + { + validateKeyUsage(KeyUsage.digitalSignature); + return ClientCertificateType.rsa_sign; + } + + /* + * DSA public key; the certificate MUST allow the key to be used for signing with the + * hash algorithm that will be employed in the certificate verify message. + */ + if (publicKey instanceof DSAPublicKeyParameters) + { + validateKeyUsage(KeyUsage.digitalSignature); + return ClientCertificateType.dss_sign; + } + + /* + * ECDSA-capable public key; the certificate MUST allow the key to be used for signing + * with the hash algorithm that will be employed in the certificate verify message; the + * public key MUST use a curve and point format supported by the server. + */ + if (publicKey instanceof ECPublicKeyParameters) + { + validateKeyUsage(KeyUsage.digitalSignature); + // TODO Check the curve and point format + return ClientCertificateType.ecdsa_sign; + } + + // TODO Add support for ClientCertificateType.*_fixed_* + } + catch (IOException e) + { + throw e; + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e); + } + + throw new TlsFatalAlert(AlertDescription.unsupported_certificate); + } + + public byte[] getEncoded() throws IOException + { + return certificate.getEncoded(ASN1Encoding.DER); + } + + protected DHPublicKeyParameters getPubKeyDH() throws IOException + { + DHPublicKeyParameters pubKeyDH; + try + { + pubKeyDH = (DHPublicKeyParameters)getPublicKey(); + } + catch (ClassCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + + return validatePubKeyDH(pubKeyDH); + } + + public DSAPublicKeyParameters getPubKeyDSS() throws IOException + { + DSAPublicKeyParameters pubKeyDSS; + try + { + pubKeyDSS = (DSAPublicKeyParameters)getPublicKey(); + } + catch (ClassCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + + return validatePubKeyDSS(pubKeyDSS); + } + + public ECPublicKeyParameters getPubKeyEC() throws IOException + { + ECPublicKeyParameters pubKeyEC; + try + { + pubKeyEC = (ECPublicKeyParameters)getPublicKey(); + } + catch (ClassCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + + return validatePubKeyEC(pubKeyEC); + } + + public RSAKeyParameters getPubKeyRSA() throws IOException + { + RSAKeyParameters pubKeyRSA; + try + { + pubKeyRSA = (RSAKeyParameters)getPublicKey(); + } + catch (ClassCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + + return validatePubKeyRSA(pubKeyRSA); + } + + public TlsCertificate useInRole(int connectionEnd, int keyExchangeAlgorithm) throws IOException + { + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DH_RSA: + { + validateKeyUsage(KeyUsage.keyAgreement); + this.pubKeyDH = getPubKeyDH(); + return this; + } + + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDH_RSA: + { + validateKeyUsage(KeyUsage.keyAgreement); + this.pubKeyEC = getPubKeyEC(); + return this; + } + } + + if (connectionEnd == ConnectionEnd.server) + { + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.RSA: + case KeyExchangeAlgorithm.RSA_PSK: + { + validateKeyUsage(KeyUsage.keyEncipherment); + this.pubKeyRSA = getPubKeyRSA(); + return this; + } + } + } + + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + + protected AsymmetricKeyParameter getPublicKey() throws IOException + { + SubjectPublicKeyInfo keyInfo = certificate.getSubjectPublicKeyInfo(); + try + { + return PublicKeyFactory.createKey(keyInfo); + } + catch (RuntimeException e) + { + throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e); + } + } + + protected void validateKeyUsage(int keyUsageBits) + throws IOException + { + Extensions exts = certificate.getTBSCertificate().getExtensions(); + if (exts != null) + { + KeyUsage ku = KeyUsage.fromExtensions(exts); + if (ku != null) + { + int bits = ku.getBytes()[0] & 0xff; + if ((bits & keyUsageBits) != keyUsageBits) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + } + } + } + + protected DHPublicKeyParameters validatePubKeyDH(DHPublicKeyParameters pubKeyDH) throws IOException + { + TlsDHUtils.validateDHPublicValues(pubKeyDH.getY(), pubKeyDH.getParameters().getP()); + + return pubKeyDH; + } + + protected DSAPublicKeyParameters validatePubKeyDSS(DSAPublicKeyParameters pubKeyDSS) throws IOException + { + // TODO[tls-ops] + return pubKeyDSS; + } + + protected ECPublicKeyParameters validatePubKeyEC(ECPublicKeyParameters pubKeyEC) throws IOException + { + // TODO[tls-ops] + return pubKeyEC; + } + + protected RSAKeyParameters validatePubKeyRSA(RSAKeyParameters pubKeyRSA) throws IOException + { + // TODO[tls-ops] + return pubKeyRSA; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java 2016-12-22 02:11:44.000000000 +0000 @@ -0,0 +1,974 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.CryptoException; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.ExtendedDigest; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.RuntimeCryptoException; +import org.bouncycastle.crypto.StreamCipher; +import org.bouncycastle.crypto.agreement.srp.SRP6Client; +import org.bouncycastle.crypto.agreement.srp.SRP6Server; +import org.bouncycastle.crypto.agreement.srp.SRP6VerifierGenerator; +import org.bouncycastle.crypto.digests.MD5Digest; +import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.digests.SHA224Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.encodings.PKCS1Encoding; +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.engines.CamelliaEngine; +import org.bouncycastle.crypto.engines.ChaCha7539Engine; +import org.bouncycastle.crypto.engines.DESedeEngine; +import org.bouncycastle.crypto.engines.RC4Engine; +import org.bouncycastle.crypto.engines.RSABlindedEngine; +import org.bouncycastle.crypto.engines.SEEDEngine; +import org.bouncycastle.crypto.macs.HMac; +import org.bouncycastle.crypto.macs.Poly1305; +import org.bouncycastle.crypto.modes.AEADBlockCipher; +import org.bouncycastle.crypto.modes.CBCBlockCipher; +import org.bouncycastle.crypto.modes.CCMBlockCipher; +import org.bouncycastle.crypto.modes.GCMBlockCipher; +import org.bouncycastle.crypto.modes.OCBBlockCipher; +import org.bouncycastle.crypto.params.AEADParameters; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.crypto.params.SRP6GroupParameters; +import org.bouncycastle.crypto.prng.DigestRandomGenerator; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.CombinedHash; +import org.bouncycastle.tls.EncryptionAlgorithm; +import org.bouncycastle.tls.HashAlgorithm; +import org.bouncycastle.tls.MACAlgorithm; +import org.bouncycastle.tls.PRFAlgorithm; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsDHDomain; +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.tls.crypto.TlsECDomain; +import org.bouncycastle.tls.crypto.TlsHMAC; +import org.bouncycastle.tls.crypto.TlsHash; +import org.bouncycastle.tls.crypto.TlsMAC; +import org.bouncycastle.tls.crypto.TlsSRP6Client; +import org.bouncycastle.tls.crypto.TlsSRP6Server; +import org.bouncycastle.tls.crypto.TlsSRP6VerifierGenerator; +import org.bouncycastle.tls.crypto.TlsSRPConfig; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.tls.crypto.impl.AbstractTlsCrypto; +import org.bouncycastle.tls.crypto.impl.ChaCha20Poly1305Cipher; +import org.bouncycastle.tls.crypto.impl.TlsAEADCipher; +import org.bouncycastle.tls.crypto.impl.TlsAEADCipherImpl; +import org.bouncycastle.tls.crypto.impl.TlsBlockCipher; +import org.bouncycastle.tls.crypto.impl.TlsBlockCipherImpl; +import org.bouncycastle.tls.crypto.impl.TlsEncryptor; +import org.bouncycastle.tls.crypto.impl.TlsImplUtils; +import org.bouncycastle.tls.crypto.impl.TlsNullCipher; +import org.bouncycastle.tls.crypto.impl.TlsStreamCipher; +import org.bouncycastle.tls.crypto.impl.TlsStreamCipherImpl; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Times; + +/** + * Class for providing cryptographic services for TLS based on implementations in the BC light-weight API. + *

      + * This class provides default implementations for everything. If you need to customise it, extend the class + * and override the appropriate methods. + *

      + */ +public class BcTlsCrypto + extends AbstractTlsCrypto +{ + private final DigestRandomGenerator nonceGen; + private final SecureRandom entropySource; + + public BcTlsCrypto(SecureRandom entropySource) + { + this.entropySource = entropySource; + + Digest digest = createDigest(HashAlgorithm.sha256); + + nonceGen = new DigestRandomGenerator(digest); + + nonceGen.addSeedMaterial(nextCounterValue()); + nonceGen.addSeedMaterial(Times.nanoTime()); + + byte[] seed = new byte[digest.getDigestSize()]; + entropySource.nextBytes(seed); + + nonceGen.addSeedMaterial(seed); + } + + BcTlsSecret adoptLocalSecret(byte[] data) + { + return new BcTlsSecret(this, data); + } + + public byte[] createNonce(int size) + { + byte[] nonce = new byte[size]; + + nonceGen.nextBytes(nonce); + + return nonce; + } + + + public SecureRandom getSecureRandom() + { + return entropySource; + } + + public TlsCertificate createCertificate(byte[] encoding) + throws IOException + { + return new BcTlsCertificate(this, encoding); + } + + protected TlsCipher createCipher(TlsCryptoParameters cryptoParams, int encryptionAlgorithm, int macAlgorithm) + throws IOException + { + switch (encryptionAlgorithm) + { + case EncryptionAlgorithm._3DES_EDE_CBC: + return createDESedeCipher(cryptoParams, macAlgorithm); + case EncryptionAlgorithm.AES_128_CBC: + return createAESCipher(cryptoParams, 16, macAlgorithm); + case EncryptionAlgorithm.AES_128_CCM: + // NOTE: Ignores macAlgorithm + return createCipher_AES_CCM(cryptoParams, 16, 16); + case EncryptionAlgorithm.AES_128_CCM_8: + // NOTE: Ignores macAlgorithm + return createCipher_AES_CCM(cryptoParams, 16, 8); + case EncryptionAlgorithm.AES_128_GCM: + // NOTE: Ignores macAlgorithm + return createCipher_AES_GCM(cryptoParams, 16, 16); + case EncryptionAlgorithm.AES_128_OCB_TAGLEN96: + // NOTE: Ignores macAlgorithm + return createCipher_AES_OCB(cryptoParams, 16, 12); + case EncryptionAlgorithm.AES_256_CBC: + return createAESCipher(cryptoParams, 32, macAlgorithm); + case EncryptionAlgorithm.AES_256_CCM: + // NOTE: Ignores macAlgorithm + return createCipher_AES_CCM(cryptoParams, 32, 16); + case EncryptionAlgorithm.AES_256_CCM_8: + // NOTE: Ignores macAlgorithm + return createCipher_AES_CCM(cryptoParams, 32, 8); + case EncryptionAlgorithm.AES_256_GCM: + // NOTE: Ignores macAlgorithm + return createCipher_AES_GCM(cryptoParams, 32, 16); + case EncryptionAlgorithm.AES_256_OCB_TAGLEN96: + // NOTE: Ignores macAlgorithm + return createCipher_AES_OCB(cryptoParams, 32, 12); + case EncryptionAlgorithm.CAMELLIA_128_CBC: + return createCamelliaCipher(cryptoParams, 16, macAlgorithm); + case EncryptionAlgorithm.CAMELLIA_128_GCM: + // NOTE: Ignores macAlgorithm + return createCipher_Camellia_GCM(cryptoParams, 16, 16); + case EncryptionAlgorithm.CAMELLIA_256_CBC: + return createCamelliaCipher(cryptoParams, 32, macAlgorithm); + case EncryptionAlgorithm.CAMELLIA_256_GCM: + // NOTE: Ignores macAlgorithm + return createCipher_Camellia_GCM(cryptoParams, 32, 16); + case EncryptionAlgorithm.CHACHA20_POLY1305: + // NOTE: Ignores macAlgorithm + return createChaCha20Poly1305(cryptoParams); + case EncryptionAlgorithm.NULL: + return createNullCipher(cryptoParams, macAlgorithm); + case EncryptionAlgorithm.RC4_128: + return createRC4Cipher(cryptoParams, 16, macAlgorithm); + case EncryptionAlgorithm.SEED_CBC: + return createSEEDCipher(cryptoParams, macAlgorithm); + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public TlsDHDomain createDHDomain(TlsDHConfig dhConfig) + { + return new BcTlsDHDomain(this, dhConfig); + } + + public TlsECDomain createECDomain(TlsECConfig ecConfig) + { + return new BcTlsECDomain(this, ecConfig); + } + + protected TlsEncryptor createEncryptor(TlsCertificate certificate) + throws IOException + { + BcTlsCertificate bcCert = BcTlsCertificate.convert(this, certificate); + bcCert.validateKeyUsage(KeyUsage.keyEncipherment); + + final RSAKeyParameters pubKeyRSA = bcCert.getPubKeyRSA(); + + return new TlsEncryptor() + { + public byte[] encrypt(byte[] input, int inOff, int length) + throws IOException + { + try + { + PKCS1Encoding encoding = new PKCS1Encoding(new RSABlindedEngine()); + encoding.init(true, new ParametersWithRandom(pubKeyRSA, getSecureRandom())); + return encoding.processBlock(input, inOff, length); + } + catch (InvalidCipherTextException e) + { + /* + * This should never happen, only during decryption. + */ + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } + }; + } + + public boolean hasEncryptionAlgorithm(int encryptionAlgorithm) + { + return true; + } + + public boolean hasHashAlgorithm(short hashAlgorithm) + { + return true; + } + + public boolean hasMacAlgorithm(int macAlgorithm) + { + return true; + } + + public boolean hasSignatureAndHashAlgorithm(SignatureAndHashAlgorithm sigAndHashAlgorithm) + { + return true; + } + + public boolean hasRSAEncryption() + { + return true; + } + + public TlsSecret createSecret(byte[] data) + { + try + { + return adoptLocalSecret(Arrays.clone(data)); + } + finally + { + // TODO[tls-ops] Add this after checking all callers +// if (data != null) +// { +// Arrays.fill(data, (byte)0); +// } + } + } + + public TlsSecret generateRSAPreMasterSecret(ProtocolVersion version) + { + byte[] data = new byte[48]; + entropySource.nextBytes(data); + TlsUtils.writeVersion(version, data, 0); + return adoptLocalSecret(data); + } + +// public byte[] calculateKeyBlock(TlsContext context, int length) +// { +// SecurityParameters securityParameters = context.getSecurityParameters(); +// byte[] master_secret = securityParameters.getMasterSecret(); +// byte[] seed = concat(securityParameters.getServerRandom(), securityParameters.getClientRandom()); +// +// if (isSSL(context)) +// { +// return context.getCrypto().createSecret(master_secret).deriveSSLKeyBlock(seed, length).extract(); +// } +// +// return PRF(context, master_secret, ExporterLabel.key_expansion, seed, length); +// } + + // TODO[tls-ops] Shouldn't be static, need to pass BcTlsCrypto instance to callers + static Digest createDigest(short hashAlgorithm) + { + switch (hashAlgorithm) + { + case HashAlgorithm.md5: + return new MD5Digest(); + case HashAlgorithm.sha1: + return new SHA1Digest(); + case HashAlgorithm.sha224: + return new SHA224Digest(); + case HashAlgorithm.sha256: + return new SHA256Digest(); + case HashAlgorithm.sha384: + return new SHA384Digest(); + case HashAlgorithm.sha512: + return new SHA512Digest(); + default: + throw new IllegalArgumentException("unknown HashAlgorithm"); + } + } + + public TlsHash createHash(final SignatureAndHashAlgorithm signatureAndHashAlgorithm) + { + if (signatureAndHashAlgorithm == null) + { + return new CombinedHash(this); + } + + return new BcTlsHash(signatureAndHashAlgorithm.getHash(), createDigest(signatureAndHashAlgorithm.getHash())); + } + + public TlsHash createHash(short algorithm) + { + return new BcTlsHash(algorithm, createDigest(algorithm)); + } + + private static class BcTlsHash + implements TlsHash + { + private final short hashAlgorithm; + private final Digest digest; + + BcTlsHash(short hashAlgorithm, Digest digest) + { + this.hashAlgorithm = hashAlgorithm; + this.digest = digest; + } + + public void update(byte[] data, int offSet, int length) + { + digest.update(data, offSet, length); + } + + public byte[] calculateHash() + { + byte[] rv = new byte[digest.getDigestSize()]; + + digest.doFinal(rv, 0); + + return rv; + } + + public Object clone() + { + return new BcTlsHash(hashAlgorithm, cloneDigest(hashAlgorithm, digest)); + } + + public void reset() + { + digest.reset(); + } + } + + public static Digest cloneDigest(short hashAlgorithm, Digest hash) + { + switch (hashAlgorithm) + { + case HashAlgorithm.md5: + return new MD5Digest((MD5Digest)hash); + case HashAlgorithm.sha1: + return new SHA1Digest((SHA1Digest)hash); + case HashAlgorithm.sha224: + return new SHA224Digest((SHA224Digest)hash); + case HashAlgorithm.sha256: + return new SHA256Digest((SHA256Digest)hash); + case HashAlgorithm.sha384: + return new SHA384Digest((SHA384Digest)hash); + case HashAlgorithm.sha512: + return new SHA512Digest((SHA512Digest)hash); + default: + throw new IllegalArgumentException("unknown HashAlgorithm"); + } + } + + public Digest createPRFHash(int prfAlgorithm) + { + switch (prfAlgorithm) + { + case PRFAlgorithm.tls_prf_legacy: + return new CombinedPRF(); + default: + return createDigest(TlsUtils.getHashAlgorithmForPRFAlgorithm(prfAlgorithm)); + } + } + + protected TlsCipher createAESCipher(TlsCryptoParameters cryptoParams, int cipherKeySize, int macAlgorithm) + throws IOException + { + return new TlsBlockCipher(this, cryptoParams, new BlockOperator(createAESBlockCipher(), true), new BlockOperator(createAESBlockCipher(), false), + createMac(cryptoParams, macAlgorithm), createMac(cryptoParams, macAlgorithm), cipherKeySize); + } + + protected TlsCipher createCamelliaCipher(TlsCryptoParameters cryptoParams, int cipherKeySize, int macAlgorithm) + throws IOException + { + return new TlsBlockCipher(this, cryptoParams, new BlockOperator(createCamelliaBlockCipher(), true), new BlockOperator(createCamelliaBlockCipher(), false), + createMac(cryptoParams, macAlgorithm), createMac(cryptoParams, macAlgorithm), cipherKeySize); + } + + protected TlsCipher createChaCha20Poly1305(TlsCryptoParameters cryptoParams) + throws IOException + { + return new ChaCha20Poly1305Cipher(cryptoParams, + new StreamOperator(new ChaCha7539Engine(), true), new StreamOperator(new ChaCha7539Engine(), false), + new MacOperator(new Poly1305()), new MacOperator(new Poly1305())); + } + + protected TlsAEADCipher createCipher_AES_CCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) + throws IOException + { + return new TlsAEADCipher(cryptoParams, new AeadOperator(createAEADBlockCipher_AES_CCM(), true), new AeadOperator(createAEADBlockCipher_AES_CCM(), false), + cipherKeySize, macSize); + } + + protected TlsAEADCipher createCipher_AES_GCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) + throws IOException + { + return new TlsAEADCipher(cryptoParams, new AeadOperator(createAEADBlockCipher_AES_GCM(), true), new AeadOperator(createAEADBlockCipher_AES_GCM(), false), + cipherKeySize, macSize); + } + + protected TlsAEADCipher createCipher_AES_OCB(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) + throws IOException + { + return new TlsAEADCipher(cryptoParams, new AeadOperator(createAEADBlockCipher_AES_OCB(), true), new AeadOperator(createAEADBlockCipher_AES_OCB(), false), + cipherKeySize, macSize, TlsAEADCipher.NONCE_RFC7905); + } + + protected TlsAEADCipher createCipher_Camellia_GCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) + throws IOException + { + return new TlsAEADCipher(cryptoParams, new AeadOperator(createAEADBlockCipher_Camellia_GCM(), true), new AeadOperator(createAEADBlockCipher_Camellia_GCM(), false), + cipherKeySize, macSize); + } + + protected TlsBlockCipher createDESedeCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws IOException + { + return new TlsBlockCipher(this, cryptoParams, new BlockOperator(createDESedeBlockCipher(), true), new BlockOperator(createDESedeBlockCipher(), false), + createMac(cryptoParams, macAlgorithm), createMac(cryptoParams, macAlgorithm), 24); + } + + protected TlsNullCipher createNullCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws IOException + { + return new TlsNullCipher(cryptoParams, createMac(cryptoParams, macAlgorithm), createMac(cryptoParams, macAlgorithm)); + } + + protected TlsStreamCipher createRC4Cipher(TlsCryptoParameters cryptoParams, int cipherKeySize, int macAlgorithm) + throws IOException + { + return new TlsStreamCipher(cryptoParams, new StreamOperator(createRC4StreamCipher(), true), new StreamOperator(createRC4StreamCipher(), false), + createMac(cryptoParams, macAlgorithm), createMac(cryptoParams, macAlgorithm), cipherKeySize, false); + } + + protected TlsBlockCipher createSEEDCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws IOException + { + return new TlsBlockCipher(this, cryptoParams, new BlockOperator(createSEEDBlockCipher(), true), new BlockOperator(createSEEDBlockCipher(), false), + createMac(cryptoParams, macAlgorithm), createMac(cryptoParams, macAlgorithm), 16); + } + + protected BlockCipher createAESEngine() + { + return new AESEngine(); + } + + protected BlockCipher createCamelliaEngine() + { + return new CamelliaEngine(); + } + + protected BlockCipher createAESBlockCipher() + { + return new CBCBlockCipher(createAESEngine()); + } + + protected AEADBlockCipher createAEADBlockCipher_AES_CCM() + { + return new CCMBlockCipher(createAESEngine()); + } + + protected AEADBlockCipher createAEADBlockCipher_AES_GCM() + { + // TODO Consider allowing custom configuration of multiplier + return new GCMBlockCipher(createAESEngine()); + } + + protected AEADBlockCipher createAEADBlockCipher_AES_OCB() + { + return new OCBBlockCipher(createAESEngine(), createAESEngine()); + } + + protected AEADBlockCipher createAEADBlockCipher_Camellia_GCM() + { + // TODO Consider allowing custom configuration of multiplier + return new GCMBlockCipher(createCamelliaEngine()); + } + + protected BlockCipher createCamelliaBlockCipher() + { + return new CBCBlockCipher(createCamelliaEngine()); + } + + protected BlockCipher createDESedeBlockCipher() + { + return new CBCBlockCipher(new DESedeEngine()); + } + + protected StreamCipher createRC4StreamCipher() + { + return new RC4Engine(); + } + + protected BlockCipher createSEEDBlockCipher() + { + return new CBCBlockCipher(new SEEDEngine()); + } + + private TlsHMAC createMac(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws IOException + { + if (TlsImplUtils.isSSL(cryptoParams)) + { + return createSSl3HMAC((short)macAlgorithm); + } + else + { + return createHMAC((short)macAlgorithm); + } + } + + protected Digest createHMACDigest(int macAlgorithm) + throws IOException + { + switch (macAlgorithm) + { + case MACAlgorithm._null: + return null; + case MACAlgorithm.hmac_md5: + return createDigest(HashAlgorithm.md5); + case MACAlgorithm.hmac_sha1: + return createDigest(HashAlgorithm.sha1); + case MACAlgorithm.hmac_sha256: + return createDigest(HashAlgorithm.sha256); + case MACAlgorithm.hmac_sha384: + return createDigest(HashAlgorithm.sha384); + case MACAlgorithm.hmac_sha512: + return createDigest(HashAlgorithm.sha512); + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public TlsHMAC createHMAC(int hashAlgorithm) + { + switch (hashAlgorithm) + { + case MACAlgorithm.hmac_md5: + return new HMacOperator(createDigest(HashAlgorithm.md5)); + case MACAlgorithm.hmac_sha1: + return new HMacOperator(createDigest(HashAlgorithm.sha1)); + case MACAlgorithm.hmac_sha256: + return new HMacOperator(createDigest(HashAlgorithm.sha256)); + case MACAlgorithm.hmac_sha384: + return new HMacOperator(createDigest(HashAlgorithm.sha384)); + case MACAlgorithm.hmac_sha512: + return new HMacOperator(createDigest(HashAlgorithm.sha512)); + default: + throw new IllegalArgumentException("unknown HashAlgorithm"); + } + } + + public TlsSRP6Client createSRP6Client(TlsSRPConfig srpConfig) + { + final SRP6Client srpClient = new SRP6Client(); + + BigInteger[] ng = srpConfig.getExplicitNG(); + SRP6GroupParameters srpGroup= new SRP6GroupParameters(ng[0], ng[1]); + srpClient.init(srpGroup, new SHA1Digest(), this.getSecureRandom()); + + return new TlsSRP6Client() + { + public BigInteger calculateSecret(BigInteger serverB) + throws TlsFatalAlert + { + try + { + return srpClient.calculateSecret(serverB); + } + catch (CryptoException e) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); + } + } + + public BigInteger generateClientCredentials(byte[] srpSalt, byte[] identity, byte[] password) + { + return srpClient.generateClientCredentials(srpSalt, identity, password); + } + }; + } + + public TlsSRP6Server createSRP6Server(TlsSRPConfig srpConfig, BigInteger srpVerifier) + { + final SRP6Server srpServer = new SRP6Server(); + BigInteger[] ng = srpConfig.getExplicitNG(); + SRP6GroupParameters srpGroup= new SRP6GroupParameters(ng[0], ng[1]); + srpServer.init(srpGroup, srpVerifier, new SHA1Digest(), this.getSecureRandom()); + return new TlsSRP6Server() + { + public BigInteger generateServerCredentials() + { + return srpServer.generateServerCredentials(); + } + + public BigInteger calculateSecret(BigInteger clientA) + throws IOException + { + try + { + return srpServer.calculateSecret(clientA); + } + catch (CryptoException e) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); + } + } + }; + } + + public TlsSRP6VerifierGenerator createSRP6VerifierGenerator(TlsSRPConfig srpConfig) + { + BigInteger[] ng = srpConfig.getExplicitNG(); + final SRP6VerifierGenerator verifierGenerator = new SRP6VerifierGenerator(); + + verifierGenerator.init(ng[0], ng[1], new SHA1Digest()); + + return new TlsSRP6VerifierGenerator() + { + public BigInteger generateVerifier(byte[] salt, byte[] identity, byte[] password) + { + return verifierGenerator.generateVerifier(salt, identity, password); + } + }; + } + + protected TlsHMAC createSSl3HMAC(int macAlgorithm) + throws IOException + { + switch (macAlgorithm) + { + case MACAlgorithm._null: + return null; + case MACAlgorithm.hmac_md5: + return new SSL3Mac(createDigest(HashAlgorithm.md5)); + case MACAlgorithm.hmac_sha1: + return new SSL3Mac(createDigest(HashAlgorithm.sha1)); + case MACAlgorithm.hmac_sha256: + return new SSL3Mac(createDigest(HashAlgorithm.sha256)); + case MACAlgorithm.hmac_sha384: + return new SSL3Mac(createDigest(HashAlgorithm.sha384)); + case MACAlgorithm.hmac_sha512: + return new SSL3Mac(createDigest(HashAlgorithm.sha512)); + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public class CombinedPRF + implements Digest + { + private final MD5Digest md5; + private final SHA1Digest sha1; + + CombinedPRF() + { + this.md5 = new MD5Digest(); + this.sha1 = new SHA1Digest(); + } + + /** + * @see org.bouncycastle.crypto.Digest#getAlgorithmName() + */ + public String getAlgorithmName() + { + return md5.getAlgorithmName() + " and " + sha1.getAlgorithmName(); + } + + /** + * @see org.bouncycastle.crypto.Digest#getDigestSize() + */ + public int getDigestSize() + { + return md5.getDigestSize() + sha1.getDigestSize(); + } + + /** + * @see org.bouncycastle.crypto.Digest#update(byte) + */ + public void update(byte input) + { + md5.update(input); + sha1.update(input); + } + + /** + * @see org.bouncycastle.crypto.Digest#update(byte[], int, int) + */ + public void update(byte[] input, int inOff, int len) + { + md5.update(input, inOff, len); + sha1.update(input, inOff, len); + } + + /** + * @see org.bouncycastle.crypto.Digest#doFinal(byte[], int) + */ + public int doFinal(byte[] output, int outOff) + { + int i1 = md5.doFinal(output, outOff); + int i2 = sha1.doFinal(output, outOff + i1); + return i1 + i2; + } + + /** + * @see org.bouncycastle.crypto.Digest#reset() + */ + public void reset() + { + md5.reset(); + sha1.reset(); + } + } + + private class BlockOperator + implements TlsBlockCipherImpl + { + private final boolean isEncrypting; + private final BlockCipher cipher; + + private KeyParameter key; + + BlockOperator(BlockCipher cipher, boolean isEncrypting) + { + this.cipher = cipher; + this.isEncrypting = isEncrypting; + } + + public void setKey(byte[] key) + { + this.key = new KeyParameter(key); + cipher.init(isEncrypting, new ParametersWithIV(this.key, new byte[cipher.getBlockSize()])); + } + + public void init(byte[] iv) + { + cipher.init(isEncrypting, new ParametersWithIV(null, iv)); + } + + public int doFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) + { + int blockSize = cipher.getBlockSize(); + + for (int i = 0; i < inputLength; i += blockSize) + { + cipher.processBlock(input, inputOffset + i, output, outputOffset + i); + } + + return inputLength; + } + + public int getBlockSize() + { + return cipher.getBlockSize(); + } + } + + private class StreamOperator + implements TlsStreamCipherImpl + { + private final boolean isEncrypting; + private final StreamCipher cipher; + + private KeyParameter key; + + StreamOperator(StreamCipher cipher, boolean isEncrypting) + { + this.cipher = cipher; + this.isEncrypting = isEncrypting; + } + + public void setKey(byte[] key) + { + this.key = new KeyParameter(key); + } + + public void init(byte[] iv) + { + if (iv != null) + { + cipher.init(isEncrypting, new ParametersWithIV(this.key, iv)); + } + else + { + cipher.init(isEncrypting, this.key); + } + } + + public int doFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) + { + return cipher.processBytes(input, inputOffset, inputLength, output, outputOffset); + } + } + + public class AeadOperator + implements TlsAEADCipherImpl + { + private final boolean isEncrypting; + private final AEADBlockCipher cipher; + + private KeyParameter key; + + public AeadOperator(AEADBlockCipher cipher, boolean isEncrypting) + { + this.cipher = cipher; + this.isEncrypting = isEncrypting; + } + + public void setKey(byte[] key) + { + this.key = new KeyParameter(key); + } + + public void init(byte[] nonce, int macSize, byte[] additionalData) + { + cipher.init(isEncrypting, new AEADParameters(key, macSize * 8, nonce, additionalData)); + } + + public int getOutputSize(int inputLength) + { + return cipher.getOutputSize(inputLength); + } + + public int doFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) + { + int len = cipher.processBytes(input, inputOffset, inputLength, output, outputOffset); + + try + { + return len + cipher.doFinal(output, outputOffset + len); + } + catch (InvalidCipherTextException e) + { + // TODO: + e.printStackTrace(); throw new RuntimeCryptoException(e.toString()); + } + } + } + + private class MacOperator implements TlsMAC + { + private final Mac mac; + + MacOperator(Mac mac) + { + this.mac = mac; + } + + public void setKey(byte[] key) + { + mac.init(new KeyParameter(key)); + } + + public void update(byte[] input, int inOff, int length) + { + mac.update(input, inOff, length); + } + + public byte[] calculateMAC() + { + byte[] rv = new byte[mac.getMacSize()]; + + mac.doFinal(rv, 0); + + return rv; + } + + public int getMacLength() + { + return mac.getMacSize(); + } + + public void reset() + { + mac.reset(); + } + } + + private class HMacOperator implements TlsHMAC + { + private final HMac hmac; + + HMacOperator(Digest digest) + { + this.hmac = new HMac(digest); + } + + public void setKey(byte[] key) + { + hmac.init(new KeyParameter(key)); + } + + public void update(byte[] input, int inOff, int length) + { + hmac.update(input, inOff, length); + } + + public byte[] calculateMAC() + { + byte[] rv = new byte[hmac.getMacSize()]; + + hmac.doFinal(rv, 0); + + return rv; + } + + public int getInternalBlockSize() + { + return ((ExtendedDigest)hmac.getUnderlyingDigest()).getByteLength(); + } + + public int getMacLength() + { + return hmac.getMacSize(); + } + + public void reset() + { + hmac.reset(); + } + } + + private static long counter = Times.nanoTime(); + + private synchronized static long nextCounterValue() + { + return ++counter; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDHDomain.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDHDomain.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDHDomain.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDHDomain.java 2016-10-09 00:47:20.000000000 +0000 @@ -0,0 +1,109 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import java.io.IOException; +import java.math.BigInteger; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.agreement.DHBasicAgreement; +import org.bouncycastle.crypto.generators.DHBasicKeyPairGenerator; +import org.bouncycastle.crypto.params.DHKeyGenerationParameters; +import org.bouncycastle.crypto.params.DHParameters; +import org.bouncycastle.crypto.params.DHPrivateKeyParameters; +import org.bouncycastle.crypto.params.DHPublicKeyParameters; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsDHDomain; +import org.bouncycastle.util.BigIntegers; + +/** + * BC light-weight support class for Diffie-Hellman key pair generation and key agreement over a specified Diffie-Hellman configuration. + */ +public class BcTlsDHDomain implements TlsDHDomain +{ + protected BcTlsCrypto crypto; + protected TlsDHConfig dhConfig; + protected DHParameters dhDomain; + + public BcTlsDHDomain(BcTlsCrypto crypto, TlsDHConfig dhConfig) + { + this.crypto = crypto; + this.dhConfig = dhConfig; + this.dhDomain = getParameters(dhConfig); + } + + public byte[] calculateDHAgreement(DHPublicKeyParameters publicKey, DHPrivateKeyParameters privateKey) + { + DHBasicAgreement basicAgreement = new DHBasicAgreement(); + basicAgreement.init(privateKey); + BigInteger agreementValue = basicAgreement.calculateAgreement(publicKey); + + /* + * RFC 5246 8.1.2. Leading bytes of Z that contain all zero bits are stripped before it is + * used as the pre_master_secret. + */ + return BigIntegers.asUnsignedByteArray(agreementValue); + } + + public TlsAgreement createDH() + { + return new BcTlsDH(this); + } + + public static BigInteger decodeParameter(byte[] encoding) throws IOException + { + return new BigInteger(1, encoding); + } + + public DHPublicKeyParameters decodePublicKey(byte[] encoding) throws IOException + { + try + { + BigInteger y = decodeParameter(encoding); + + // TODO Check RFCs for any validation that could/should be done here + + return new DHPublicKeyParameters(y, dhDomain); + } + catch (RuntimeException e) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); + } + } + + public byte[] encodeParameter(BigInteger x) throws IOException + { + return BigIntegers.asUnsignedByteArray(x); + } + + public byte[] encodePublicKey(DHPublicKeyParameters publicKey) throws IOException + { + return encodeParameter(publicKey.getY()); + } + + public AsymmetricCipherKeyPair generateKeyPair() + { + DHBasicKeyPairGenerator keyPairGenerator = new DHBasicKeyPairGenerator(); + keyPairGenerator.init(new DHKeyGenerationParameters(crypto.getSecureRandom(), dhDomain)); + return keyPairGenerator.generateKeyPair(); + } + + public BcTlsCrypto getCrypto() + { + return crypto; + } + + public DHParameters getParameters(TlsDHConfig dhConfig) + { + // TODO There's a draft RFC for negotiated (named) groups + + BigInteger[] pg = dhConfig.getExplicitPG(); + if (pg != null) + { + return new DHParameters(pg[0], pg[1]); + } + + throw new IllegalStateException("No DH configuration provided"); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDH.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDH.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDH.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDH.java 2016-10-09 00:47:20.000000000 +0000 @@ -0,0 +1,46 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import java.io.IOException; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.params.DHPrivateKeyParameters; +import org.bouncycastle.crypto.params.DHPublicKeyParameters; +import org.bouncycastle.tls.TlsDHUtils; +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsSecret; + +/** + * Support class for ephemeral Diffie-Hellman using the BC light-weight library. + */ +public class BcTlsDH implements TlsAgreement +{ + protected BcTlsDHDomain domain; + protected AsymmetricCipherKeyPair localKeyPair; + protected DHPublicKeyParameters peerPublicKey; + + public BcTlsDH(BcTlsDHDomain domain) + { + this.domain = domain; + } + + public byte[] generateEphemeral() throws IOException + { + this.localKeyPair = domain.generateKeyPair(); + return domain.encodePublicKey((DHPublicKeyParameters)localKeyPair.getPublic()); + } + + public void receivePeerValue(byte[] peerValue) throws IOException + { + DHPublicKeyParameters dhKey = domain.decodePublicKey(peerValue); + + TlsDHUtils.validateDHPublicValues(dhKey.getY(), dhKey.getParameters().getP()); + + this.peerPublicKey = dhKey; + } + + public TlsSecret calculateSecret() throws IOException + { + byte[] data = domain.calculateDHAgreement(peerPublicKey, (DHPrivateKeyParameters)localKeyPair.getPrivate()); + return domain.getCrypto().adoptLocalSecret(data); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSASigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSASigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSASigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSASigner.java 2016-10-10 00:12:59.000000000 +0000 @@ -0,0 +1,29 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.signers.DSASigner; +import org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import org.bouncycastle.tls.SignatureAlgorithm; + +/** + * Implementation class for generation of the raw DSA signature type using the BC light-weight API. + */ +public class BcTlsDSASigner + extends BcTlsDSSSigner +{ + public BcTlsDSASigner(BcTlsCrypto crypto, AsymmetricKeyParameter privateKey) + { + super(crypto, privateKey); + } + + protected DSA createDSAImpl(short hashAlgorithm) + { + return new DSASigner(new HMacDSAKCalculator(BcTlsCrypto.createDigest(hashAlgorithm))); + } + + protected short getSignatureAlgorithm() + { + return SignatureAlgorithm.dsa; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSAVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSAVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSAVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSAVerifier.java 2016-10-10 00:25:19.000000000 +0000 @@ -0,0 +1,29 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import org.bouncycastle.crypto.signers.DSASigner; +import org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import org.bouncycastle.tls.SignatureAlgorithm; + +/** + * Implementation class for the verification of the raw DSA signature type using the BC light-weight API. + */ +public class BcTlsDSAVerifier + extends BcTlsDSSVerifier +{ + public BcTlsDSAVerifier(BcTlsCrypto crypto, DSAPublicKeyParameters pubKeyDSA) + { + super(crypto, pubKeyDSA); + } + + protected DSA createDSAImpl(short hashAlgorithm) + { + return new DSASigner(new HMacDSAKCalculator(crypto.createDigest(hashAlgorithm))); + } + + protected short getSignatureAlgorithm() + { + return SignatureAlgorithm.dsa; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSSSigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSSSigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSSSigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSSSigner.java 2016-10-09 23:49:45.000000000 +0000 @@ -0,0 +1,78 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import java.io.IOException; + +import org.bouncycastle.crypto.CryptoException; +import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.digests.NullDigest; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.signers.DSADigestSigner; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.HashAlgorithm; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.TlsSigner; + +/** + * BC light-weight base class for the signers implementing the two DSA style algorithms from FIPS PUB 186-4: DSA and ECDSA. + */ +public abstract class BcTlsDSSSigner + implements TlsSigner +{ + private final AsymmetricKeyParameter privateKey; + private final BcTlsCrypto crypto; + + protected BcTlsDSSSigner(BcTlsCrypto crypto, AsymmetricKeyParameter privateKey) + { + this.crypto = crypto; + + if (privateKey == null) + { + throw new IllegalArgumentException("'privateKey' cannot be null"); + } + if (!privateKey.isPrivate()) + { + throw new IllegalArgumentException("'privateKey' must be private"); + } + + this.privateKey = privateKey; + } + + protected abstract DSA createDSAImpl(short hashAlgorithm); + + protected abstract short getSignatureAlgorithm(); + + public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, + byte[] hash) throws IOException + { + if (algorithm != null && algorithm.getSignature() != getSignatureAlgorithm()) + { + throw new IllegalStateException(); + } + + short hashAlgorithm = algorithm == null ? HashAlgorithm.sha1 : algorithm.getHash(); + + Signer s = new DSADigestSigner(createDSAImpl(hashAlgorithm), new NullDigest()); + s.init(true, new ParametersWithRandom(privateKey, crypto.getSecureRandom())); + Signer signer = s; + if (algorithm == null) + { + // Note: Only use the SHA1 part of the (MD5/SHA1) hash + signer.update(hash, 16, 20); + } + else + { + signer.update(hash, 0, hash.length); + } + try + { + return signer.generateSignature(); + } + catch (CryptoException e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSSVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSSVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSSVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDSSVerifier.java 2016-10-10 00:25:06.000000000 +0000 @@ -0,0 +1,64 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.digests.NullDigest; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.signers.DSADigestSigner; +import org.bouncycastle.tls.DigitallySigned; +import org.bouncycastle.tls.HashAlgorithm; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.crypto.TlsVerifier; + +/** + * BC light-weight base class for the verifiers supporting the two DSA style algorithms from FIPS PUB 186-4: DSA and ECDSA. + */ +public abstract class BcTlsDSSVerifier + implements TlsVerifier +{ + protected final AsymmetricKeyParameter pubKey; + protected final BcTlsCrypto crypto; + + protected BcTlsDSSVerifier(BcTlsCrypto crypto, AsymmetricKeyParameter pubKey) + { + if (pubKey == null) + { + throw new IllegalArgumentException("'pubKey' cannot be null"); + } + if (pubKey.isPrivate()) + { + throw new IllegalArgumentException("'pubKey' must be a public key"); + } + + this.crypto = crypto; + this.pubKey = pubKey; + } + + protected abstract DSA createDSAImpl(short hashAlgorithm); + + protected abstract short getSignatureAlgorithm(); + + public boolean verifySignature(DigitallySigned signedParams, byte[] hash) + { + SignatureAndHashAlgorithm algorithm = signedParams.getAlgorithm(); + if (algorithm != null && algorithm.getSignature() != getSignatureAlgorithm()) + { + throw new IllegalStateException(); + } + + short hashAlgorithm = algorithm == null ? HashAlgorithm.sha1 : algorithm.getHash(); + + Signer signer = new DSADigestSigner(createDSAImpl(hashAlgorithm), new NullDigest()); + signer.init(false, pubKey); + if (algorithm == null) + { + // Note: Only use the SHA1 part of the (MD5/SHA1) hash + signer.update(hash, 16, 20); + } + else + { + signer.update(hash, 0, hash.length); + } + return signer.verifySignature(signedParams.getSignature()); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDH.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDH.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDH.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDH.java 2016-10-09 00:47:20.000000000 +0000 @@ -0,0 +1,41 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import java.io.IOException; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsSecret; + +/** + * Support class for ephemeral Elliptic Curve Diffie-Hellman using the BC light-weight library. + */ +public class BcTlsECDH implements TlsAgreement +{ + protected BcTlsECDomain domain; + protected AsymmetricCipherKeyPair localKeyPair; + protected ECPublicKeyParameters peerPublicKey; + + public BcTlsECDH(BcTlsECDomain domain) + { + this.domain = domain; + } + + public byte[] generateEphemeral() throws IOException + { + this.localKeyPair = domain.generateKeyPair(); + return domain.encodePublicKey((ECPublicKeyParameters)localKeyPair.getPublic()); + } + + public void receivePeerValue(byte[] peerValue) throws IOException + { + this.peerPublicKey = domain.decodePublicKey(peerValue); + } + + public TlsSecret calculateSecret() throws IOException + { + byte[] data = domain.calculateECDHAgreement(peerPublicKey, (ECPrivateKeyParameters)localKeyPair.getPrivate()); + return domain.getCrypto().adoptLocalSecret(data); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java 2016-11-05 03:48:02.000000000 +0000 @@ -0,0 +1,131 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import java.io.IOException; +import java.math.BigInteger; + +import org.bouncycastle.asn1.x9.ECNamedCurveTable; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.agreement.ECDHBasicAgreement; +import org.bouncycastle.crypto.ec.CustomNamedCurves; +import org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.NamedCurve; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.tls.crypto.TlsECDomain; +import org.bouncycastle.util.BigIntegers; + +/** + * EC domain class for generating key pairs and performing key agreement. + */ +public class BcTlsECDomain implements TlsECDomain +{ + protected BcTlsCrypto crypto; + protected TlsECConfig ecConfig; + protected ECDomainParameters ecDomain; + + public BcTlsECDomain(BcTlsCrypto crypto, TlsECConfig ecConfig) + { + this.crypto = crypto; + this.ecConfig = ecConfig; + this.ecDomain = getParameters(ecConfig); + } + + public byte[] calculateECDHAgreement(ECPublicKeyParameters publicKey, ECPrivateKeyParameters privateKey) + { + ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement(); + basicAgreement.init(privateKey); + BigInteger agreementValue = basicAgreement.calculateAgreement(publicKey); + + /* + * RFC 4492 5.10. Note that this octet string (Z in IEEE 1363 terminology) as output by + * FE2OSP, the Field Element to Octet String Conversion Primitive, has constant length for + * any given field; leading zeros found in this octet string MUST NOT be truncated. + */ + return BigIntegers.asUnsignedByteArray(basicAgreement.getFieldSize(), agreementValue); + } + + public TlsAgreement createECDH() + { + return new BcTlsECDH(this); + } + + public ECPoint decodePoint(byte[] encoding) throws IOException + { + return ecDomain.getCurve().decodePoint(encoding); + } + + public ECPublicKeyParameters decodePublicKey(byte[] encoding) throws IOException + { + try + { + ECPoint point = decodePoint(encoding); + + // TODO Check RFCs for any validation that could/should be done here + + return new ECPublicKeyParameters(point, ecDomain); + } + catch (RuntimeException e) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); + } + } + + public byte[] encodePoint(ECPoint point) throws IOException + { + return point.getEncoded(ecConfig.getPointCompression()); + } + + public byte[] encodePublicKey(ECPublicKeyParameters publicKey) throws IOException + { + return encodePoint(publicKey.getQ()); + } + + public AsymmetricCipherKeyPair generateKeyPair() + { + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + keyPairGenerator.init(new ECKeyGenerationParameters(ecDomain, crypto.getSecureRandom())); + return keyPairGenerator.generateKeyPair(); + } + + public BcTlsCrypto getCrypto() + { + return crypto; + } + + public ECDomainParameters getParameters(TlsECConfig ecConfig) + { + return getParametersForNamedCurve(ecConfig.getNamedCurve()); + } + + public ECDomainParameters getParametersForNamedCurve(int namedCurve) + { + String curveName = NamedCurve.getNameOfSpecificCurve(namedCurve); + if (curveName == null) + { + return null; + } + + // Parameters are lazily created the first time a particular curve is accessed + + X9ECParameters ecP = CustomNamedCurves.getByName(curveName); + if (ecP == null) + { + ecP = ECNamedCurveTable.getByName(curveName); + if (ecP == null) + { + return null; + } + } + + // It's a bit inefficient to do this conversion every time + return new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDSASigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDSASigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDSASigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDSASigner.java 2016-10-10 00:10:52.000000000 +0000 @@ -0,0 +1,29 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.signers.ECDSASigner; +import org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import org.bouncycastle.tls.SignatureAlgorithm; + +/** + * Implementation class for generation of the raw ECDSA signature type using the BC light-weight API. + */ +public class BcTlsECDSASigner + extends BcTlsDSSSigner +{ + public BcTlsECDSASigner(BcTlsCrypto crypto, AsymmetricKeyParameter privateKey) + { + super(crypto, privateKey); + } + + protected DSA createDSAImpl(short hashAlgorithm) + { + return new ECDSASigner(new HMacDSAKCalculator(BcTlsCrypto.createDigest(hashAlgorithm))); + } + + protected short getSignatureAlgorithm() + { + return SignatureAlgorithm.ecdsa; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDSAVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDSAVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDSAVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDSAVerifier.java 2016-10-10 00:25:06.000000000 +0000 @@ -0,0 +1,29 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.signers.ECDSASigner; +import org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import org.bouncycastle.tls.SignatureAlgorithm; + +/** + * Implementation class for the verification of the raw ECDSA signature type using the BC light-weight API. + */ +public class BcTlsECDSAVerifier + extends BcTlsDSSVerifier +{ + public BcTlsECDSAVerifier(BcTlsCrypto crypto, ECPublicKeyParameters pubKeyEC) + { + super(crypto, pubKeyEC); + } + + protected DSA createDSAImpl(short hashAlgorithm) + { + return new ECDSASigner(new HMacDSAKCalculator(crypto.createDigest(hashAlgorithm))); + } + + protected short getSignatureAlgorithm() + { + return SignatureAlgorithm.ecdsa; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRSASigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRSASigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRSASigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRSASigner.java 2016-11-05 03:49:09.000000000 +0000 @@ -0,0 +1,81 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import java.io.IOException; + +import org.bouncycastle.crypto.CryptoException; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.digests.NullDigest; +import org.bouncycastle.crypto.encodings.PKCS1Encoding; +import org.bouncycastle.crypto.engines.RSABlindedEngine; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.signers.GenericSigner; +import org.bouncycastle.crypto.signers.RSADigestSigner; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsSigner; + +/** + * Operator supporting the generation of RSA signatures using the BC light-weight API. + */ +public class BcTlsRSASigner + implements TlsSigner +{ + private final AsymmetricKeyParameter privateKey; + private final BcTlsCrypto crypto; + + public BcTlsRSASigner(BcTlsCrypto crypto, AsymmetricKeyParameter privateKey) + { + this.crypto = crypto; + if (privateKey == null) + { + throw new IllegalArgumentException("'privateKey' cannot be null"); + } + if (!privateKey.isPrivate()) + { + throw new IllegalArgumentException("'privateKey' must be private"); + } + + this.privateKey = privateKey; + } + + public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, + byte[] hash) throws IOException + { + Signer signer; + if (algorithm != null) + { + if (algorithm.getSignature() != SignatureAlgorithm.rsa) + { + throw new IllegalStateException(); + } + + /* + * RFC 5246 4.7. In RSA signing, the opaque vector contains the signature generated + * using the RSASSA-PKCS1-v1_5 signature scheme defined in [PKCS1]. + */ + signer = new RSADigestSigner(new NullDigest(), TlsUtils.getOIDForHashAlgorithm(algorithm.getHash())); + } + else + { + /* + * RFC 5246 4.7. Note that earlier versions of TLS used a different RSA signature scheme + * that did not include a DigestInfo encoding. + */ + signer = new GenericSigner(new PKCS1Encoding(new RSABlindedEngine()), new NullDigest()); + } + signer.init(true, new ParametersWithRandom(privateKey, crypto.getSecureRandom())); + signer.update(hash, 0, hash.length); + try + { + return signer.generateSignature(); + } + catch (CryptoException e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRSAVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRSAVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRSAVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRSAVerifier.java 2016-11-05 03:49:09.000000000 +0000 @@ -0,0 +1,67 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.digests.NullDigest; +import org.bouncycastle.crypto.encodings.PKCS1Encoding; +import org.bouncycastle.crypto.engines.RSABlindedEngine; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.crypto.signers.GenericSigner; +import org.bouncycastle.crypto.signers.RSADigestSigner; +import org.bouncycastle.tls.DigitallySigned; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsVerifier; + +/** + * Operator supporting the verification of RSA signatures using the BC light-weight API. + */ +public class BcTlsRSAVerifier + implements TlsVerifier +{ + protected RSAKeyParameters pubKeyRSA; + + public BcTlsRSAVerifier(RSAKeyParameters pubKeyRSA) + { + if (pubKeyRSA == null) + { + throw new IllegalArgumentException("'pubKeyRSA' cannot be null"); + } + if (pubKeyRSA.isPrivate()) + { + throw new IllegalArgumentException("'pubKeyRSA' must be a public key"); + } + + this.pubKeyRSA = pubKeyRSA; + } + + public boolean verifySignature(DigitallySigned signedParams, byte[] hash) + { + SignatureAndHashAlgorithm algorithm = signedParams.getAlgorithm(); + Signer signer; + if (algorithm != null) + { + if (algorithm.getSignature() != SignatureAlgorithm.rsa) + { + throw new IllegalStateException(); + } + + /* + * RFC 5246 4.7. In RSA signing, the opaque vector contains the signature generated + * using the RSASSA-PKCS1-v1_5 signature scheme defined in [PKCS1]. + */ + signer = new RSADigestSigner(new NullDigest(), TlsUtils.getOIDForHashAlgorithm(algorithm.getHash())); + } + else + { + /* + * RFC 5246 4.7. Note that earlier versions of TLS used a different RSA signature scheme + * that did not include a DigestInfo encoding. + */ + signer = new GenericSigner(new PKCS1Encoding(new RSABlindedEngine()), new NullDigest()); + } + signer.init(false, pubKeyRSA); + signer.update(hash, 0, hash.length); + return signer.verifySignature(signedParams.getSignature()); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSecret.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSecret.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSecret.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSecret.java 2016-10-09 00:50:05.000000000 +0000 @@ -0,0 +1,138 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.macs.HMac; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.tls.HashAlgorithm; +import org.bouncycastle.tls.PRFAlgorithm; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.tls.crypto.impl.AbstractTlsCrypto; +import org.bouncycastle.tls.crypto.impl.AbstractTlsSecret; +import org.bouncycastle.util.Arrays; + +/** + * BC light-weight support class for handling TLS secrets and deriving key material and other secrets from them. + */ +public class BcTlsSecret + extends AbstractTlsSecret +{ + protected final BcTlsCrypto crypto; + + public BcTlsSecret(BcTlsCrypto crypto, byte[] data) + { + super(data); + + this.crypto = crypto; + } + + protected AbstractTlsCrypto getCrypto() + { + return crypto; + } + + public synchronized TlsSecret deriveSSLKeyBlock(byte[] seed, int length) + { + checkAlive(); + + int md5Count = (length + MD5_SIZE - 1) / MD5_SIZE; + byte[] md5Buf = prf_SSL(seed, md5Count); + + TlsSecret result = crypto.adoptLocalSecret(Arrays.copyOfRange(md5Buf, 0, length)); + Arrays.fill(md5Buf, (byte)0); + return result; + } + + public synchronized TlsSecret deriveSSLMasterSecret(byte[] seed) + { + checkAlive(); + return crypto.adoptLocalSecret(prf_SSL(seed, 3)); + } + + public synchronized TlsSecret deriveUsingPRF(int prfAlgorithm, byte[] labelSeed, int length) + { + checkAlive(); + + byte[] result = (prfAlgorithm == PRFAlgorithm.tls_prf_legacy) + ? prf_1_0(data, labelSeed, length) + : prf_1_2(crypto.createPRFHash(prfAlgorithm), data, labelSeed, length); + + return crypto.adoptLocalSecret(result); + } + + protected void hmacHash(Digest digest, byte[] secret, byte[] seed, byte[] output) + { + HMac mac = new HMac(digest); + mac.init(new KeyParameter(secret)); + byte[] a = seed; + int size = digest.getDigestSize(); + int iterations = (output.length + size - 1) / size; + byte[] b1 = new byte[mac.getMacSize()]; + byte[] b2 = new byte[mac.getMacSize()]; + for (int i = 0; i < iterations; i++) + { + mac.update(a, 0, a.length); + mac.doFinal(b1, 0); + a = b1; + mac.update(a, 0, a.length); + mac.update(seed, 0, seed.length); + mac.doFinal(b2, 0); + System.arraycopy(b2, 0, output, (size * i), Math.min(size, output.length - (size * i))); + } + } + + protected byte[] prf_SSL(byte[] seed, int md5Count) + { + Digest md5 = crypto.createDigest(HashAlgorithm.md5); + Digest sha1 = crypto.createDigest(HashAlgorithm.sha1); + + int md5Size = md5.getDigestSize(); + byte[] md5Buf = new byte[md5Size * md5Count]; + int md5Pos = 0; + + byte[] sha1Buf = new byte[sha1.getDigestSize()]; + + for (int i = 0; i < md5Count; ++i) + { + byte[] ssl3Const = SSL3_CONST[i]; + + sha1.update(ssl3Const, 0, ssl3Const.length); + sha1.update(data, 0, data.length); + sha1.update(seed, 0, seed.length); + sha1.doFinal(sha1Buf, 0); + + md5.update(data, 0, data.length); + md5.update(sha1Buf, 0, sha1Buf.length); + md5.doFinal(md5Buf, md5Pos); + + md5Pos += md5Size; + } + + return md5Buf; + } + + protected byte[] prf_1_0(byte[] secret, byte[] labelSeed, int length) + { + int s_half = (secret.length + 1) / 2; + byte[] s1 = new byte[s_half]; + byte[] s2 = new byte[s_half]; + System.arraycopy(secret, 0, s1, 0, s_half); + System.arraycopy(secret, secret.length - s_half, s2, 0, s_half); + + byte[] b1 = new byte[length]; + byte[] b2 = new byte[length]; + hmacHash(crypto.createDigest(HashAlgorithm.md5), s1, labelSeed, b1); + hmacHash(crypto.createDigest(HashAlgorithm.sha1), s2, labelSeed, b2); + for (int i = 0; i < length; i++) + { + b1[i] ^= b2[i]; + } + return b1; + } + + protected byte[] prf_1_2(Digest prfDigest, byte[] secret, byte[] labelSeed, int length) + { + byte[] result = new byte[length]; + hmacHash(prfDigest, secret, labelSeed, result); + return result; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/SSL3Mac.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/SSL3Mac.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/SSL3Mac.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/SSL3Mac.java 2016-10-09 00:52:59.000000000 +0000 @@ -0,0 +1,144 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.ExtendedDigest; +import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.tls.crypto.TlsHMAC; +import org.bouncycastle.util.Arrays; + +/** + * HMAC implementation based on original internet draft for HMAC (RFC 2104). + *
      + * The difference is that padding is concatenated versus XORed with the key, e.g: + *
      + *   H(K + opad, H(K + ipad, text))
      + * 
      + * + */ +public class SSL3Mac + implements Mac, TlsHMAC +{ + private static final byte IPAD_BYTE = (byte)0x36; + private static final byte OPAD_BYTE = (byte)0x5C; + + private static final byte[] IPAD = genPad(IPAD_BYTE, 48); + private static final byte[] OPAD = genPad(OPAD_BYTE, 48); + + private Digest digest; + private int padLength; + + private byte[] secret; + + /** + * Base constructor for one of the standard digest algorithms that the byteLength of + * the algorithm is know for. Behaviour is undefined for digests other than MD5 or SHA1. + * + * @param digest the digest. + */ + public SSL3Mac(Digest digest) + { + this.digest = digest; + + if (digest.getDigestSize() == 20) + { + this.padLength = 40; + } + else + { + this.padLength = 48; + } + } + + public String getAlgorithmName() + { + return digest.getAlgorithmName() + "/SSL3MAC"; + } + + public Digest getUnderlyingDigest() + { + return digest; + } + + public void init(CipherParameters params) + { + secret = Arrays.clone(((KeyParameter)params).getKey()); + + reset(); + } + + public int getMacSize() + { + return digest.getDigestSize(); + } + + public void update(byte in) + { + digest.update(in); + } + + public void setKey(byte[] key) + { + secret = Arrays.clone(key); + + reset(); + } + + public void update(byte[] in, int inOff, int len) + { + digest.update(in, inOff, len); + } + + public byte[] calculateMAC() + { + byte[] rv = new byte[digest.getDigestSize()]; + + doFinal(rv, 0); + + return rv; + } + + public int getInternalBlockSize() + { + return ((ExtendedDigest)digest).getByteLength(); + } + + public int getMacLength() + { + return digest.getDigestSize(); + } + + public int doFinal(byte[] out, int outOff) + { + byte[] tmp = new byte[digest.getDigestSize()]; + digest.doFinal(tmp, 0); + + digest.update(secret, 0, secret.length); + digest.update(OPAD, 0, padLength); + digest.update(tmp, 0, tmp.length); + + int len = digest.doFinal(out, outOff); + + reset(); + + return len; + } + + /** + * Reset the mac generator. + */ + public void reset() + { + digest.reset(); + digest.update(secret, 0, secret.length); + digest.update(IPAD, 0, padLength); + } + + private static byte[] genPad(byte b, int count) + { + byte[] padding = new byte[count]; + Arrays.fill(padding, b); + return padding; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/ChaCha20Poly1305Cipher.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/ChaCha20Poly1305Cipher.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/ChaCha20Poly1305Cipher.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/ChaCha20Poly1305Cipher.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,222 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsMAC; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; + +/** + * Cipher suite specified in RFC 7905 using ChaCha20 and Poly1305. + */ +public class ChaCha20Poly1305Cipher + implements TlsCipher +{ + private static final byte[] ZEROES = new byte[15]; + + protected TlsCryptoParameters context; + + protected TlsMAC writeMac; + protected TlsMAC readMac; + + protected TlsStreamCipherImpl encryptCipher; + protected TlsStreamCipherImpl decryptCipher; + + protected byte[] encryptIV, decryptIV; + + public ChaCha20Poly1305Cipher(TlsCryptoParameters context, TlsStreamCipherImpl encryptCipher, TlsStreamCipherImpl decryptCipher, + TlsMAC writeMac, TlsMAC readMac) + throws IOException + { + if (!TlsImplUtils.isTLSv12(context)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.context = context; + + int cipherKeySize = 32; + // TODO SecurityParameters.fixed_iv_length + int fixed_iv_length = 12; + // TODO SecurityParameters.record_iv_length = 0 + + int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length); + + byte[] key_block = TlsImplUtils.calculateKeyBlock(context, key_block_size); + + int offset = 0; + + byte[] client_write_key = Arrays.copyOfRange(key_block, offset, offset + cipherKeySize); + offset += cipherKeySize; + byte[] server_write_key = Arrays.copyOfRange(key_block, offset, offset + cipherKeySize); + offset += cipherKeySize; + byte[] client_write_IV = Arrays.copyOfRange(key_block, offset, offset + fixed_iv_length); + offset += fixed_iv_length; + byte[] server_write_IV = Arrays.copyOfRange(key_block, offset, offset + fixed_iv_length); + offset += fixed_iv_length; + + if (offset != key_block_size) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.writeMac = writeMac; + this.readMac = readMac; + this.encryptCipher = encryptCipher; + this.decryptCipher = decryptCipher; + + byte[] encryptKey, decryptKey; + if (context.isServer()) + { + encryptKey = server_write_key; + decryptKey = client_write_key; + this.encryptIV = server_write_IV; + this.decryptIV = client_write_IV; + } + else + { + encryptKey = client_write_key; + decryptKey = server_write_key; + this.encryptIV = client_write_IV; + this.decryptIV = server_write_IV; + } + + this.encryptCipher.setKey(encryptKey); + this.encryptCipher.init(encryptIV); + this.decryptCipher.setKey(decryptKey); + this.decryptCipher.init(decryptIV); + } + + public int getPlaintextLimit(int ciphertextLimit) + { + return ciphertextLimit - 16; + } + + public byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len) throws IOException + { + initRecord(encryptCipher, seqNo, encryptIV); + + // MAC key is from the zeros at the front. + byte[] cipherOut = new byte[64 + len]; + System.arraycopy(plaintext, offset, cipherOut, 64, len); + + encryptCipher.doFinal(cipherOut, 0, cipherOut.length, cipherOut, 0); + + byte[] output = new byte[len + 16]; + byte[] macKey = Arrays.copyOfRange(cipherOut, 0, 32); + System.arraycopy(cipherOut, 64, output, 0, len); + + Arrays.fill(cipherOut, (byte)0); + + writeMac.setKey(macKey); + + byte[] additionalData = getAdditionalData(seqNo, type, len); + byte[] mac = calculateRecordMAC(writeMac, additionalData, output, 0, len); + System.arraycopy(mac, 0, output, len, mac.length); + + return output; + } + + public byte[] decodeCiphertext(long seqNo, short type, byte[] ciphertext, int offset, int len) throws IOException + { + if (getPlaintextLimit(len) < 0) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + initRecord(decryptCipher, seqNo, decryptIV); + int plaintextLength = len - 16; + + // MAC key is from the zeros at the front. + byte[] cipherOut = new byte[64 + plaintextLength]; + System.arraycopy(ciphertext, offset, cipherOut, 64, plaintextLength); + + decryptCipher.doFinal(cipherOut, 0, cipherOut.length, cipherOut, 0); + + byte[] macKey = Arrays.copyOfRange(cipherOut, 0, 32); + readMac.setKey(macKey); + + byte[] additionalData = getAdditionalData(seqNo, type, plaintextLength); + byte[] calculatedMAC = calculateRecordMAC(readMac, additionalData, ciphertext, offset, plaintextLength); + byte[] receivedMAC = Arrays.copyOfRange(ciphertext, offset + plaintextLength, offset + len); + byte[] output = new byte[plaintextLength]; + + System.arraycopy(cipherOut, 64, output, 0, plaintextLength); + + Arrays.fill(cipherOut, (byte)0); + + if (!Arrays.constantTimeAreEqual(calculatedMAC, receivedMAC)) + { + throw new TlsFatalAlert(AlertDescription.bad_record_mac); + } + + return output; + } + + protected void initRecord(TlsStreamCipherImpl cipher, long seqNo, byte[] iv) + throws IOException + { + byte[] nonce = calculateNonce(seqNo, iv); + cipher.init(nonce); + } + + protected byte[] calculateNonce(long seqNo, byte[] iv) + { + byte[] nonce = new byte[12]; + TlsUtils.writeUint64(seqNo, nonce, 4); + + for (int i = 0; i < 12; ++i) + { + nonce[i] ^= iv[i]; + } + + return nonce; + } + + protected byte[] calculateRecordMAC(TlsMAC mac, byte[] additionalData, byte[] buf, int off, int len) + { + updateRecordMACText(mac, additionalData, 0, additionalData.length); + updateRecordMACText(mac, buf, off, len); + updateRecordMACLength(mac, additionalData.length); + updateRecordMACLength(mac, len); + + return mac.calculateMAC(); + } + + protected void updateRecordMACLength(TlsMAC mac, int len) + { + byte[] longLen = Pack.longToLittleEndian(len & 0xFFFFFFFFL); + mac.update(longLen, 0, longLen.length); + } + + protected void updateRecordMACText(TlsMAC mac, byte[] buf, int off, int len) + { + mac.update(buf, off, len); + + int partial = len % 16; + if (partial != 0) + { + mac.update(ZEROES, 0, 16 - partial); + } + } + + protected byte[] getAdditionalData(long seqNo, short type, int len) throws IOException + { + /* + * additional_data = seq_num + TLSCompressed.type + TLSCompressed.version + + * TLSCompressed.length + */ + byte[] additional_data = new byte[13]; + TlsUtils.writeUint64(seqNo, additional_data, 0); + TlsUtils.writeUint8(type, additional_data, 8); + TlsUtils.writeVersion(context.getServerVersion(), additional_data, 9); + TlsUtils.writeUint16(len, additional_data, 11); + + return additional_data; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaDefaultTlsCredentialedSigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaDefaultTlsCredentialedSigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaDefaultTlsCredentialedSigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaDefaultTlsCredentialedSigner.java 2016-12-16 22:25:43.000000000 +0000 @@ -0,0 +1,47 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.PrivateKey; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.RSAPrivateKey; + +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.DefaultTlsCredentialedSigner; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsSigner; + +/** + * Credentialed class for generating signatures based on the use of primitives from the JCA. + */ +public class JcaDefaultTlsCredentialedSigner + extends DefaultTlsCredentialedSigner +{ + private static TlsSigner makeSigner(JcaTlsCrypto crypto, PrivateKey privateKey) + { + TlsSigner signer; + if (privateKey instanceof RSAPrivateKey || "RSA".equals(privateKey.getAlgorithm())) + { + signer = new JcaTlsRSASigner(crypto, privateKey); + } + else if (privateKey instanceof DSAPrivateKey || "DSA".equals(privateKey.getAlgorithm())) + { + signer = new JcaTlsDSASigner(crypto, privateKey); + } + else if (privateKey instanceof ECPrivateKey || "EC".equals(privateKey.getAlgorithm())) + { + signer = new JcaTlsECDSASigner(crypto, privateKey); + } + else + { + throw new IllegalArgumentException("'privateKey' type not supported: " + privateKey.getClass().getName()); + } + + return signer; + } + + public JcaDefaultTlsCredentialedSigner(TlsCryptoParameters cryptoParams, JcaTlsCrypto crypto, PrivateKey privateKey, Certificate certificate, SignatureAndHashAlgorithm signatureAndHashAlgorithm) + { + super(cryptoParams, makeSigner(crypto, privateKey), certificate, signatureAndHashAlgorithm); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java 2016-11-13 04:25:45.000000000 +0000 @@ -0,0 +1,331 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PublicKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; + +import javax.crypto.interfaces.DHPublicKey; + +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.asn1.x509.TBSCertificate; +import org.bouncycastle.jcajce.util.JcaJceHelper; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.ConnectionEnd; +import org.bouncycastle.tls.KeyExchangeAlgorithm; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsVerifier; + +/** + * Implementation class for a single X.509 certificate based on the JCA. + */ +public class JcaTlsCertificate + implements TlsCertificate +{ + private final JcaJceHelper helper; + + public static JcaTlsCertificate convert(TlsCertificate certificate, JcaJceHelper helper) throws IOException + { + if (certificate instanceof JcaTlsCertificate) + { + return (JcaTlsCertificate)certificate; + } + + return new JcaTlsCertificate(certificate.getEncoded(), helper); + } + + protected final X509Certificate certificate; + + protected DHPublicKey pubKeyDH = null; + protected ECPublicKey pubKeyEC = null; + protected RSAPublicKey pubKeyRSA = null; + + public JcaTlsCertificate(byte[] encoding, JcaJceHelper helper) + throws IOException + { + try + { + ByteArrayInputStream input = new ByteArrayInputStream(encoding); + this.certificate = (X509Certificate)helper.createCertificateFactory("X.509").generateCertificate(input); + if (input.available() != 0) + { + throw new IOException("Extra data detected in stream"); + } + } + catch (GeneralSecurityException e) + { + throw new IOException("unable to decode certificate: " + e.getMessage(), e); + } + this.helper = helper; + } + + public TlsVerifier createVerifier(short signatureAlgorithm) throws IOException + { + validateKeyUsage(KeyUsage.digitalSignature); + + switch (signatureAlgorithm) + { + case SignatureAlgorithm.dsa: + return new JcaTlsDSAVerifier(getPubKeyDSS(), helper); + + case SignatureAlgorithm.ecdsa: + return new JcaTlsECDSAVerifier(getPubKeyEC(), helper); + + case SignatureAlgorithm.rsa: + return new JcaTlsRSAVerifier(getPubKeyRSA(), helper); + + default: + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + } + + public short getClientCertificateType() throws IOException + { + PublicKey publicKey = getPublicKey(); + + try + { + /* + * TODO RFC 5246 7.4.6. The certificates MUST be signed using an acceptable hash/ + * signature algorithm pair, as described in Section 7.4.4. Note that this relaxes the + * constraints on certificate-signing algorithms found in prior versions of TLS. + */ + + /* + * RFC 5246 7.4.6. Client Certificate + */ + + /* + * RSA public key; the certificate MUST allow the key to be used for signing with the + * signature scheme and hash algorithm that will be employed in the certificate verify + * message. + */ + if (publicKey instanceof RSAPublicKey) + { + validateKeyUsage(KeyUsage.digitalSignature); + return ClientCertificateType.rsa_sign; + } + + /* + * DSA public key; the certificate MUST allow the key to be used for signing with the + * hash algorithm that will be employed in the certificate verify message. + */ + if (publicKey instanceof DSAPublicKey) + { + validateKeyUsage(KeyUsage.digitalSignature); + return ClientCertificateType.dss_sign; + } + + /* + * ECDSA-capable public key; the certificate MUST allow the key to be used for signing + * with the hash algorithm that will be employed in the certificate verify message; the + * public key MUST use a curve and point format supported by the server. + */ + if (publicKey instanceof ECPublicKey) + { + validateKeyUsage(KeyUsage.digitalSignature); + // TODO Check the curve and point format + return ClientCertificateType.ecdsa_sign; + } + + // TODO Add support for ClientCertificateType.*_fixed_* + } + catch (IOException e) + { + throw e; + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e); + } + + throw new TlsFatalAlert(AlertDescription.unsupported_certificate); + } + + public byte[] getEncoded() throws IOException + { + try + { + // DER encoding enforced by provider - as defined by JCA for X.509 certificates. + return certificate.getEncoded(); + } + catch (CertificateEncodingException e) + { + throw new IOException("unable to encode certificate: " + e.getMessage(), e); + } + } + + DHPublicKey getPubKeyDH() throws IOException + { + DHPublicKey pubKeyDH; + try + { + pubKeyDH = (DHPublicKey)getPublicKey(); + } + catch (ClassCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + + return validatePubKeyDH(pubKeyDH); + } + + DSAPublicKey getPubKeyDSS() throws IOException + { + DSAPublicKey pubKeyDSS; + try + { + pubKeyDSS = (DSAPublicKey)getPublicKey(); + } + catch (ClassCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + + return validatePubKeyDSS(pubKeyDSS); + } + + ECPublicKey getPubKeyEC() throws IOException + { + ECPublicKey pubKeyEC; + try + { + pubKeyEC = (ECPublicKey)getPublicKey(); + } + catch (ClassCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + + return validatePubKeyEC(pubKeyEC); + } + + RSAPublicKey getPubKeyRSA() throws IOException + { + RSAPublicKey pubKeyRSA; + try + { + pubKeyRSA = (RSAPublicKey)getPublicKey(); + } + catch (ClassCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + + return validatePubKeyRSA(pubKeyRSA); + } + + public TlsCertificate useInRole(int connectionEnd, int keyExchangeAlgorithm) throws IOException + { + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DH_RSA: + { + validateKeyUsage(KeyUsage.keyAgreement); + this.pubKeyDH = getPubKeyDH(); + return this; + } + + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDH_RSA: + { + validateKeyUsage(KeyUsage.keyAgreement); + this.pubKeyEC = getPubKeyEC(); + return this; + } + } + + if (connectionEnd == ConnectionEnd.server) + { + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.RSA: + case KeyExchangeAlgorithm.RSA_PSK: + { + validateKeyUsage(KeyUsage.keyEncipherment); + this.pubKeyRSA = getPubKeyRSA(); + return this; + } + } + } + + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + + protected PublicKey getPublicKey() throws IOException + { + try + { + return certificate.getPublicKey(); + } + catch (RuntimeException e) + { + throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e); + } + } + + public X509Certificate getX509Certificate() + { + return certificate; + } + + protected void validateKeyUsage(int keyUsageBits) + throws IOException + { + Extensions exts; + try + { + exts = TBSCertificate.getInstance(certificate.getTBSCertificate()).getExtensions(); + } + catch (CertificateEncodingException e) + { + throw new IOException("unable to parse certificate extensions: " + e.getMessage(), e); + } + + if (exts != null) + { + KeyUsage ku = KeyUsage.fromExtensions(exts); + if (ku != null) + { + int bits = ku.getBytes()[0] & 0xff; + if ((bits & keyUsageBits) != keyUsageBits) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + } + } + } + + protected DHPublicKey validatePubKeyDH(DHPublicKey pubKeyDH) throws IOException + { + return pubKeyDH; // TODO: TlsDHUtils.validateDHPublicKey(pubKeyDH); + } + + protected DSAPublicKey validatePubKeyDSS(DSAPublicKey pubKeyDSS) throws IOException + { + // TODO[tls-ops] + return pubKeyDSS; + } + + protected ECPublicKey validatePubKeyEC(ECPublicKey pubKeyEC) throws IOException + { + // TODO[tls-ops] + return pubKeyEC; + } + + protected RSAPublicKey validatePubKeyRSA(RSAPublicKey pubKeyRSA) throws IOException + { + // TODO[tls-ops] + return pubKeyRSA; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java 2016-12-10 06:25:56.000000000 +0000 @@ -0,0 +1,778 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.security.interfaces.RSAPublicKey; + +import javax.crypto.Cipher; + +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.jcajce.util.JcaJceHelper; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.CombinedHash; +import org.bouncycastle.tls.EncryptionAlgorithm; +import org.bouncycastle.tls.HashAlgorithm; +import org.bouncycastle.tls.MACAlgorithm; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.SRP6Group; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCryptoException; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsDHDomain; +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.tls.crypto.TlsECDomain; +import org.bouncycastle.tls.crypto.TlsHMAC; +import org.bouncycastle.tls.crypto.TlsHash; +import org.bouncycastle.tls.crypto.TlsMAC; +import org.bouncycastle.tls.crypto.TlsSRP6Client; +import org.bouncycastle.tls.crypto.TlsSRP6Server; +import org.bouncycastle.tls.crypto.TlsSRP6VerifierGenerator; +import org.bouncycastle.tls.crypto.TlsSRPConfig; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.tls.crypto.impl.AbstractTlsCrypto; +import org.bouncycastle.tls.crypto.impl.ChaCha20Poly1305Cipher; +import org.bouncycastle.tls.crypto.impl.TlsAEADCipher; +import org.bouncycastle.tls.crypto.impl.TlsAEADCipherImpl; +import org.bouncycastle.tls.crypto.impl.TlsBlockCipher; +import org.bouncycastle.tls.crypto.impl.TlsBlockCipherImpl; +import org.bouncycastle.tls.crypto.impl.TlsEncryptor; +import org.bouncycastle.tls.crypto.impl.TlsImplUtils; +import org.bouncycastle.tls.crypto.impl.TlsNullCipher; +import org.bouncycastle.tls.crypto.impl.TlsStreamCipher; +import org.bouncycastle.tls.crypto.impl.TlsStreamCipherImpl; +import org.bouncycastle.tls.crypto.impl.jcajce.srp.SRP6Client; +import org.bouncycastle.tls.crypto.impl.jcajce.srp.SRP6Server; +import org.bouncycastle.tls.crypto.impl.jcajce.srp.SRP6VerifierGenerator; +import org.bouncycastle.util.Arrays; + +/** + * Class for providing cryptographic services for TLS based on implementations in the JCA/JCE. + *

      + * This class provides default implementations for everything. If you need to customise it, extend the class + * and override the appropriate methods. + *

      + */ +public class JcaTlsCrypto + extends AbstractTlsCrypto +{ + private final JcaJceHelper helper; + private final SecureRandom entropySource; + private final SecureRandom nonceEntropySource; + + /** + * Base constructor. + * + * @param helper a JCA/JCE helper configured for the class's default provider. + * @param entropySource primary entropy source, used for key generation. + * @param nonceEntropySource secondary entropy source, used for nonce and IV generation. + */ + protected JcaTlsCrypto(JcaJceHelper helper, SecureRandom entropySource, SecureRandom nonceEntropySource) + { + this.helper = helper; + this.entropySource = entropySource; + this.nonceEntropySource = nonceEntropySource; + } + + JceTlsSecret adoptLocalSecret(byte[] data) + { + return new JceTlsSecret(this, data); + } + + public byte[] createNonce(int size) + { + byte[] nonce = new byte[size]; + + nonceEntropySource.nextBytes(nonce); + + return nonce; + } + + public SecureRandom getSecureRandom() + { + return entropySource; + } + + public TlsCertificate createCertificate(byte[] encoding) + throws IOException + { + return new JcaTlsCertificate(encoding, helper); + } + + protected TlsCipher createCipher(TlsCryptoParameters cryptoParams, int encryptionAlgorithm, int macAlgorithm) + throws IOException + { + try + { + switch (encryptionAlgorithm) + { + case EncryptionAlgorithm._3DES_EDE_CBC: + return createDESedeCipher(cryptoParams, macAlgorithm); + case EncryptionAlgorithm.AES_128_CBC: + return createAESCipher(cryptoParams, 16, macAlgorithm); + case EncryptionAlgorithm.AES_128_CCM: + // NOTE: Ignores macAlgorithm + return createCipher_AES_CCM(cryptoParams, 16, 16); + case EncryptionAlgorithm.AES_128_CCM_8: + // NOTE: Ignores macAlgorithm + return createCipher_AES_CCM(cryptoParams, 16, 8); + case EncryptionAlgorithm.AES_128_GCM: + // NOTE: Ignores macAlgorithm + return createCipher_AES_GCM(cryptoParams, 16, 16); + case EncryptionAlgorithm.AES_128_OCB_TAGLEN96: + // NOTE: Ignores macAlgorithm + return createCipher_AES_OCB(cryptoParams, 16, 12); + case EncryptionAlgorithm.AES_256_CBC: + return createAESCipher(cryptoParams, 32, macAlgorithm); + case EncryptionAlgorithm.AES_256_CCM: + // NOTE: Ignores macAlgorithm + return createCipher_AES_CCM(cryptoParams, 32, 16); + case EncryptionAlgorithm.AES_256_CCM_8: + // NOTE: Ignores macAlgorithm + return createCipher_AES_CCM(cryptoParams, 32, 8); + case EncryptionAlgorithm.AES_256_GCM: + // NOTE: Ignores macAlgorithm + return createCipher_AES_GCM(cryptoParams, 32, 16); + case EncryptionAlgorithm.AES_256_OCB_TAGLEN96: + // NOTE: Ignores macAlgorithm + return createCipher_AES_OCB(cryptoParams, 32, 12); + case EncryptionAlgorithm.CAMELLIA_128_CBC: + return createCamelliaCipher(cryptoParams, 16, macAlgorithm); + case EncryptionAlgorithm.CAMELLIA_128_GCM: + // NOTE: Ignores macAlgorithm + return createCipher_Camellia_GCM(cryptoParams, 16, 16); + case EncryptionAlgorithm.CAMELLIA_256_CBC: + return createCamelliaCipher(cryptoParams, 32, macAlgorithm); + case EncryptionAlgorithm.CAMELLIA_256_GCM: + // NOTE: Ignores macAlgorithm + return createCipher_Camellia_GCM(cryptoParams, 32, 16); + case EncryptionAlgorithm.CHACHA20_POLY1305: + // NOTE: Ignores macAlgorithm + return createChaCha20Poly1305(cryptoParams); + case EncryptionAlgorithm.NULL: + return createNullCipher(cryptoParams, macAlgorithm); + case EncryptionAlgorithm.RC4_128: + return createRC4Cipher(cryptoParams, 16, macAlgorithm); + case EncryptionAlgorithm.SEED_CBC: + return createSEEDCipher(cryptoParams, macAlgorithm); + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + catch (GeneralSecurityException e) + { + throw new TlsCryptoException("cannot create cipher: " + e.getMessage(), e); + } + } + + public final TlsHMAC createHMAC(int macAlgorithm) + throws IOException + { + try + { + switch (macAlgorithm) + { + case MACAlgorithm._null: + return null; + case MACAlgorithm.hmac_md5: + return createHMAC("HmacMD5"); + case MACAlgorithm.hmac_sha1: + return createHMAC("HmacSHA1"); + case MACAlgorithm.hmac_sha256: + return createHMAC("HmacSHA256"); + case MACAlgorithm.hmac_sha384: + return createHMAC("HmacSHA384"); + case MACAlgorithm.hmac_sha512: + return createHMAC("HmacSHA512"); + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + catch (GeneralSecurityException e) + { + throw new TlsCryptoException("cannot create HMAC: " + e.getMessage(), e); + } + } + + public TlsSRP6Client createSRP6Client(TlsSRPConfig srpConfig) + { + final SRP6Client srpClient = new SRP6Client(); + + BigInteger[] ng = srpConfig.getExplicitNG(); + SRP6Group srpGroup= new SRP6Group(ng[0], ng[1]); + srpClient.init(srpGroup, createHash(HashAlgorithm.sha1), this.getSecureRandom()); + + return new TlsSRP6Client() + { + public BigInteger calculateSecret(BigInteger serverB) + throws TlsFatalAlert + { + try + { + return srpClient.calculateSecret(serverB); + } + catch (IllegalArgumentException e) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); + } + } + + public BigInteger generateClientCredentials(byte[] srpSalt, byte[] identity, byte[] password) + { + return srpClient.generateClientCredentials(srpSalt, identity, password); + } + }; + } + + public TlsSRP6Server createSRP6Server(TlsSRPConfig srpConfig, BigInteger srpVerifier) + { + final SRP6Server srpServer = new SRP6Server(); + BigInteger[] ng = srpConfig.getExplicitNG(); + SRP6Group srpGroup= new SRP6Group(ng[0], ng[1]); + srpServer.init(srpGroup, srpVerifier, createHash(HashAlgorithm.sha1), this.getSecureRandom()); + return new TlsSRP6Server() + { + public BigInteger generateServerCredentials() + { + return srpServer.generateServerCredentials(); + } + + public BigInteger calculateSecret(BigInteger clientA) + throws IOException + { + try + { + return srpServer.calculateSecret(clientA); + } + catch (IllegalArgumentException e) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); + } + } + }; + } + + public TlsSRP6VerifierGenerator createSRP6VerifierGenerator(TlsSRPConfig srpConfig) + { + BigInteger[] ng = srpConfig.getExplicitNG(); + final SRP6VerifierGenerator verifierGenerator = new SRP6VerifierGenerator(); + + verifierGenerator.init(ng[0], ng[1], createHash(HashAlgorithm.sha1)); + + return new TlsSRP6VerifierGenerator() + { + public BigInteger generateVerifier(byte[] salt, byte[] identity, byte[] password) + { + return verifierGenerator.generateVerifier(salt, identity, password); + } + }; + } + + public boolean hasEncryptionAlgorithm(int encryptionAlgorithm) + { + if (encryptionAlgorithm == EncryptionAlgorithm.CHACHA20_POLY1305) + { + try + { + helper.createCipher("ChaCha7539"); + helper.createMac("Poly1305"); + } + catch (GeneralSecurityException e) + { + return false; + } + } + + return true; + } + + public boolean hasHashAlgorithm(short hashAlgorithm) + { + // TODO: expand + return true; + } + + public boolean hasMacAlgorithm(int macAlgorithm) + { + // TODO: expand + return true; + } + + public boolean hasSignatureAndHashAlgorithm(SignatureAndHashAlgorithm sigAndHashAlgorithm) + { + // TODO: expand + return true; + } + + public boolean hasRSAEncryption() + { + // TODO: expand + return true; + } + + public TlsSecret createSecret(byte[] data) + { + try + { + return adoptLocalSecret(Arrays.clone(data)); + } + finally + { + // TODO[tls-ops] Add this after checking all callers +// if (data != null) +// { +// Arrays.fill(data, (byte)0); +// } + } + } + + public TlsSecret generateRSAPreMasterSecret(ProtocolVersion version) + { + byte[] data = new byte[48]; + getSecureRandom().nextBytes(data); + TlsUtils.writeVersion(version, data, 0); + return adoptLocalSecret(data); + } + + public TlsHash createHash(short algorithm) + { + try + { + return createHash(getDigestName(algorithm)); + } + catch (GeneralSecurityException e) + { + throw new IllegalArgumentException("unable to create message digest:" + e.getMessage(), e); + } + } + + public TlsHash createHash(final SignatureAndHashAlgorithm signatureAndHashAlgorithm) + { + if (signatureAndHashAlgorithm == null) + { + return new CombinedHash(this); + } + + return createHash(signatureAndHashAlgorithm.getHash()); + } + + public TlsDHDomain createDHDomain(TlsDHConfig dhConfig) + { + return new JceTlsDHDomain(this, dhConfig); + } + + public TlsECDomain createECDomain(TlsECConfig ecConfig) + { + return new JceTlsECDomain(this, ecConfig); + } + + public TlsEncryptor createEncryptor(TlsCertificate certificate) + throws IOException + { + JcaTlsCertificate jcaCert = JcaTlsCertificate.convert(certificate, this.getHelper()); + jcaCert.validateKeyUsage(KeyUsage.keyEncipherment); + + final RSAPublicKey pubKeyRSA = jcaCert.getPubKeyRSA(); + + return new TlsEncryptor() + { + public byte[] encrypt(byte[] input, int inOff, int length) + throws IOException + { + try + { + Cipher encoding = getHelper().createCipher("RSA/NONE/PKCS1Padding"); + encoding.init(Cipher.WRAP_MODE, pubKeyRSA, getSecureRandom()); + return encoding.doFinal(input, inOff, length); + } + catch (GeneralSecurityException e) + { + /* + * This should never happen, only during decryption. + */ + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } + }; + } + + /** + * If you want to create your own versions of the AEAD ciphers required, override this method. + * + * @param cipherName the full name of the cipher (algorithm/mode/padding) + * @param algorithm the base algorithm name + * @param keySize keySize (in bytes) for the cipher key. + * @param isEncrypting true if the cipher is for encryption, false otherwise. + * @return an AEAD cipher. + * @throws GeneralSecurityException in case of failure. + */ + protected TlsAEADCipherImpl createAEADCipher(String cipherName, String algorithm, int keySize, boolean isEncrypting) + throws GeneralSecurityException + { + return new JceAEADCipherImpl(helper.createCipher(cipherName), algorithm, isEncrypting); + } + + /** + * If you want to create your own versions of the block ciphers required, override this method. + * + * @param cipherName the full name of the cipher (algorithm/mode/padding) + * @param algorithm the base algorithm name + * @param keySize keySize (in bytes) for the cipher key. + * @param isEncrypting true if the cipher is for encryption, false otherwise. + * @return a block cipher. + * @throws GeneralSecurityException in case of failure. + */ + protected TlsBlockCipherImpl createBlockCipher(String cipherName, String algorithm, int keySize, boolean isEncrypting) + throws GeneralSecurityException + { + return new JceBlockCipherImpl(helper.createCipher(cipherName), algorithm, isEncrypting); + } + + /** + * If you want to create your own versions of the block ciphers for < TLS 1.1, override this method. + * + * @param cipherName the full name of the cipher (algorithm/mode/padding) + * @param algorithm the base algorithm name + * @param keySize keySize (in bytes) for the cipher key. + * @param isEncrypting true if the cipher is for encryption, false otherwise. + * @return a block cipher. + * @throws GeneralSecurityException in case of failure. + */ + protected TlsBlockCipherImpl createBlockCipherWithCBCImplicitIV(String cipherName, String algorithm, int keySize, boolean isEncrypting) + throws GeneralSecurityException + { + return new JceBlockCipherWithCBCImplicitIVImpl(helper.createCipher(cipherName), algorithm, isEncrypting); + } + + /** + * If you want to create your own versions of stream ciphers, override this method. + * + * @param cipherName the full name of the cipher (algorithm/mode/padding) + * @param algorithm the base algorithm name + * @param keySize keySize (in bytes) for the cipher key. + * @param isEncrypting true if the cipher is for encryption, false otherwise. + * @return a block cipher. + * @throws GeneralSecurityException in case of failure. + */ + protected TlsStreamCipherImpl createStreamCipher(String cipherName, String algorithm, int keySize, boolean isEncrypting) + throws GeneralSecurityException + { + return new JceStreamCipherImpl(helper.createCipher(cipherName), algorithm, isEncrypting); + } + + /** + * If you want to create your own versions of HMACs, override this method. + * + * @param hmacName the name of the HMAC required. + * @return a HMAC calculator. + * @throws GeneralSecurityException in case of failure. + */ + protected TlsHMAC createHMAC(String hmacName) + throws GeneralSecurityException + { + return new JceTlsHMAC(helper.createMac(hmacName), hmacName); + } + + /** + * If you want to create your own versions of MACs, override this method. + * + * @param macName the name of the MAC required. + * @return a MAC calculator. + * @throws GeneralSecurityException in case of failure. + */ + protected TlsMAC createMAC(String macName) + throws GeneralSecurityException + { + return new JceTlsMAC(helper.createMac(macName), macName); + } + + /** + * If you want to create your own versions of Hash functions, override this method. + * + * @param digestName the name of the Hash function required. + * @return a hash calculator. + * @throws GeneralSecurityException in case of failure. + */ + protected TlsHash createHash(String digestName) + throws GeneralSecurityException + { + return new JcaTlsHash(helper.createDigest(digestName)); + } + + /** + * To disable the null cipher suite, override this method with one that throws an IOException. + * + * @param macAlgorithm the name of the algorithm supporting the MAC. + * @return a null cipher suite implementation. + * @throws IOException in case of failure. + * @throws GeneralSecurityException in case of a specific failure in the JCA/JCE layer. + */ + protected TlsNullCipher createNullCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws IOException, GeneralSecurityException + { + return new TlsNullCipher(cryptoParams, createMAC(cryptoParams, macAlgorithm), createMAC(cryptoParams, macAlgorithm)); + } + + JcaJceHelper getHelper() + { + return helper; + } + + private TlsBlockCipher createAESCipher(TlsCryptoParameters cryptoParams, int cipherKeySize, int macAlgorithm) + throws IOException, GeneralSecurityException + { + return new TlsBlockCipher(this, cryptoParams, createCBCBlockOperator(cryptoParams, "AES", true, cipherKeySize), createCBCBlockOperator(cryptoParams, "AES", false, cipherKeySize), + createMAC(cryptoParams, macAlgorithm), createMAC(cryptoParams, macAlgorithm), cipherKeySize); + } + + private TlsBlockCipher createCamelliaCipher(TlsCryptoParameters cryptoParams, int cipherKeySize, int macAlgorithm) + throws IOException, GeneralSecurityException + { + return new TlsBlockCipher(this, cryptoParams, createCBCBlockOperator(cryptoParams, "Camellia", true, cipherKeySize), createCBCBlockOperator(cryptoParams, "Camellia", false, cipherKeySize), + createMAC(cryptoParams, macAlgorithm), createMAC(cryptoParams, macAlgorithm), cipherKeySize); + } + + private TlsBlockCipher createDESedeCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws IOException, GeneralSecurityException + { + return new TlsBlockCipher(this, cryptoParams, createCBCBlockOperator(cryptoParams, "DESede", true, 24), createCBCBlockOperator(cryptoParams, "DESede", false, 24), + createMAC(cryptoParams, macAlgorithm), createMAC(cryptoParams, macAlgorithm), 24); + } + + private TlsBlockCipher createSEEDCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws IOException, GeneralSecurityException + { + return new TlsBlockCipher(this, cryptoParams, createCBCBlockOperator(cryptoParams, "SEED", true, 16), createCBCBlockOperator(cryptoParams, "SEED", false, 16), + createMAC(cryptoParams, macAlgorithm), createMAC(cryptoParams, macAlgorithm), 16); + } + + private TlsBlockCipherImpl createCBCBlockOperator(TlsCryptoParameters cryptoParams, String algorithm, boolean forEncryption, int keySize) + throws GeneralSecurityException + { + String cipherName = algorithm + "/CBC/NoPadding"; + + if (TlsImplUtils.isTLSv11(cryptoParams)) + { + return createBlockCipher(cipherName, algorithm, keySize, forEncryption); + } + else + { + return createBlockCipherWithCBCImplicitIV(cipherName, algorithm, keySize, forEncryption); + } + } + + private TlsHMAC createMAC(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws GeneralSecurityException, IOException + { + if (TlsImplUtils.isSSL(cryptoParams)) + { + return createSSL3HMAC(macAlgorithm); + } + else + { + return createHMAC(macAlgorithm); + } + } + + private TlsCipher createChaCha20Poly1305(TlsCryptoParameters cryptoParams) + throws IOException, GeneralSecurityException + { + return new ChaCha20Poly1305Cipher(cryptoParams, + createStreamCipher("ChaCha7539", "ChaCha7539", 32, true), createStreamCipher("ChaCha7539", "ChaCha7539", 32, false), + createMAC("Poly1305"), createMAC("Poly1305")); + } + + private TlsAEADCipher createCipher_AES_CCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) + throws IOException, GeneralSecurityException + { + return new TlsAEADCipher(cryptoParams, createAEADCipher("AES/CCM/NoPadding", "AES", cipherKeySize, true), createAEADCipher("AES/CCM/NoPadding", "AES", cipherKeySize, false), + cipherKeySize, macSize); + } + + private TlsAEADCipher createCipher_AES_GCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) + throws IOException, GeneralSecurityException + { + return new TlsAEADCipher(cryptoParams, createAEADCipher("AES/GCM/NoPadding", "AES", cipherKeySize, true), createAEADCipher("AES/GCM/NoPadding", "AES", cipherKeySize, false), + cipherKeySize, macSize); + } + + private TlsAEADCipher createCipher_AES_OCB(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) + throws IOException, GeneralSecurityException + { + return new TlsAEADCipher(cryptoParams, createAEADCipher("AES/OCB/NoPadding", "AES", cipherKeySize, true), createAEADCipher("AES/OCB/NoPadding", "AES", cipherKeySize, false), + cipherKeySize, macSize, TlsAEADCipher.NONCE_RFC7905); + } + + private TlsAEADCipher createCipher_Camellia_GCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) + throws IOException, GeneralSecurityException + { + return new TlsAEADCipher(cryptoParams, createAEADCipher("Camellia/GCM/NoPadding", "Camellia", cipherKeySize, true), createAEADCipher("Camellia/GCM/NoPadding", "Camellia", cipherKeySize, false), + cipherKeySize, macSize); + } + + private TlsStreamCipher createRC4Cipher(TlsCryptoParameters cryptoParams, int cipherKeySize, int macAlgorithm) + throws IOException, GeneralSecurityException + { + return new TlsStreamCipher(cryptoParams, createStreamCipher("RC4", "RC4", 128, true), createStreamCipher("RC4", "RC4", 128, false), + createMAC(cryptoParams, macAlgorithm), createMAC(cryptoParams, macAlgorithm), cipherKeySize, false); + } + + private TlsHMAC createSSL3HMAC(int macAlgorithm) + throws IOException, GeneralSecurityException + { + switch (macAlgorithm) + { + case MACAlgorithm._null: + return null; + case MACAlgorithm.hmac_md5: + return new SSL3Mac(createHash(getDigestName(HashAlgorithm.md5)), 16, 64); + case MACAlgorithm.hmac_sha1: + return new SSL3Mac(createHash(getDigestName(HashAlgorithm.sha1)), 20, 64); + case MACAlgorithm.hmac_sha256: + return new SSL3Mac(createHash(getDigestName(HashAlgorithm.sha256)), 32, 64); + case MACAlgorithm.hmac_sha384: + return new SSL3Mac(createHash(getDigestName(HashAlgorithm.sha384)), 48, 128); + case MACAlgorithm.hmac_sha512: + return new SSL3Mac(createHash(getDigestName(HashAlgorithm.sha512)), 64, 128); + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + String getDigestName(short algorithm) + { + String digestName; + switch (algorithm) + { + case HashAlgorithm.md5: + digestName = "MD5"; + break; + case HashAlgorithm.sha1: + digestName = "SHA-1"; + break; + case HashAlgorithm.sha224: + digestName = "SHA-224"; + break; + case HashAlgorithm.sha256: + digestName = "SHA-256"; + break; + case HashAlgorithm.sha384: + digestName = "SHA-384"; + break; + case HashAlgorithm.sha512: + digestName = "SHA-512"; + break; + default: + throw new IllegalArgumentException("unknown HashAlgorithm"); + } + return digestName; + } + + /** + * HMAC implementation based on original internet draft for HMAC (RFC 2104) + *

      + * The difference is that padding is concatenated versus XORed with the key + *

      + * H(K + opad, H(K + ipad, text)) + */ + private static class SSL3Mac + implements TlsHMAC + { + private static final byte IPAD_BYTE = (byte)0x36; + private static final byte OPAD_BYTE = (byte)0x5C; + + private static final byte[] IPAD = genPad(IPAD_BYTE, 48); + private static final byte[] OPAD = genPad(OPAD_BYTE, 48); + + private TlsHash digest; + private final int digestSize; + private final int internalBlockSize; + private int padLength; + + private byte[] secret; + + /** + * Base constructor for one of the standard digest algorithms that the byteLength of + * the algorithm is know for. Behaviour is undefined for digests other than MD5 or SHA1. + * + * @param digest the digest. + * @param digestSize the digest size. + * @param internalBlockSize the digest internal block size. + */ + public SSL3Mac(TlsHash digest, int digestSize, int internalBlockSize) + { + this.digest = digest; + this.digestSize = digestSize; + this.internalBlockSize = internalBlockSize; + + if (digestSize == 20) + { + this.padLength = 40; + } + else + { + this.padLength = 48; + } + } + + public void setKey(byte[] key) + { + this.secret = key; + + reset(); + } + + public void update(byte[] in, int inOff, int len) + { + digest.update(in, inOff, len); + } + + public byte[] calculateMAC() + { + byte[] tmp = digest.calculateHash(); + + digest.update(secret, 0, secret.length); + digest.update(OPAD, 0, padLength); + digest.update(tmp, 0, tmp.length); + + byte[] rv = digest.calculateHash(); + + reset(); + + return rv; + } + + public int getInternalBlockSize() + { + return internalBlockSize; + } + + public int getMacLength() + { + return digestSize; + } + + /** + * Reset the mac generator. + */ + public void reset() + { + digest.reset(); + digest.update(secret, 0, secret.length); + digest.update(IPAD, 0, padLength); + } + + private static byte[] genPad(byte b, int count) + { + byte[] padding = new byte[count]; + Arrays.fill(padding, b); + return padding; + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCryptoProvider.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCryptoProvider.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCryptoProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCryptoProvider.java 2016-12-10 06:30:01.000000000 +0000 @@ -0,0 +1,195 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.DigestException; +import java.security.GeneralSecurityException; +import java.security.MessageDigest; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.SecureRandomSpi; +import java.security.Security; + +import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; +import org.bouncycastle.jcajce.util.JcaJceHelper; +import org.bouncycastle.jcajce.util.NamedJcaJceHelper; +import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsCryptoProvider; + +/** + * Basic builder class for constructing standard TlsCrypto classes. + */ +public class JcaTlsCryptoProvider + implements TlsCryptoProvider +{ + private JcaJceHelper helper = new DefaultJcaJceHelper(); + + public JcaTlsCryptoProvider() + { + } + + /** + * Set the provider of cryptographic services for any TlsCrypto we build. + * + * @param provider the provider class to source cryptographic services from. + * @return the current builder instance. + */ + public JcaTlsCryptoProvider setProvider(Provider provider) + { + this.helper = new ProviderJcaJceHelper(provider); + + return this; + } + + /** + * Set the provider of cryptographic services for any TlsCrypto we build by name. + * + * @param providerName the name of the provider class to source cryptographic services from. + * @return the current builder instance. + */ + public JcaTlsCryptoProvider setProvider(String providerName) + { + this.helper = new NamedJcaJceHelper(providerName); + + return this; + } + + /** + * Create a new TlsCrypto using the current builder configuration and the passed in entropy source.. + * + * @param random SecureRandom for generating key material and seeds for nonce generation. + * @return a new TlsCrypto. + */ + public TlsCrypto create(SecureRandom random) + { + try + { + if (random == null) + { + SecureRandom keyRandom = helper.createSecureRandom("DEFAULT"); + SecureRandom nonceRandom = helper.createSecureRandom("NONCEANDIV"); + + return create(keyRandom, nonceRandom); + } + + return create(random, new NonceEntropySource(helper, random)); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException("unable to create TlsCrypto: " + e.getMessage(), e); + } + } + + /** + * Create a new TlsCrypto using the current builder configuration. + * + * @param keyRandom SecureRandom for generating key material. + * @param nonceRandom SecureRandom for generating nonces. + * @return a new TlsCrypto. + */ + public TlsCrypto create(SecureRandom keyRandom, SecureRandom nonceRandom) + { + return new JcaTlsCrypto(helper, keyRandom, nonceRandom); + } + + public Provider getPkixProvider() + { + try + { + if (Security.getProvider("IBMCertPath") != null) + { + return Security.getProvider("IBMCertPath"); + } + return helper.createCertificateFactory("X.509").getProvider(); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException("unable to find CertificateFactory"); + } + } + + private static class NonceEntropySource + extends SecureRandom + { + NonceEntropySource(JcaJceHelper helper, SecureRandom random) + throws GeneralSecurityException + { + super(new NonceEntropySourceSpi(random, helper.createDigest("SHA-512")), null); + } + + private static class NonceEntropySourceSpi + extends SecureRandomSpi + { + private final SecureRandom source; + private final MessageDigest digest; + + private final byte[] seed; + private final byte[] state; + + public NonceEntropySourceSpi(SecureRandom source, MessageDigest digest) + { + this.source = source; + this.digest = digest; + + this.seed = source.generateSeed(digest.getDigestLength()); + this.state = new byte[seed.length]; + } + + @Override + protected void engineSetSeed(byte[] bytes) + { + digest.update(seed, 0, seed.length); + digest.update(bytes, 0, bytes.length); + + try + { + digest.digest(seed, 0, seed.length); + } + catch (DigestException e) + { + throw new IllegalStateException("unable to generate nonce data: " + e.getMessage(), e); + } + } + + @Override + protected void engineNextBytes(byte[] bytes) + { + int stateOff = 0; + + generateState(); + + for (int i = 0; i != bytes.length; i++) + { + if (stateOff == state.length) + { + generateState(); + stateOff = 0; + } + bytes[i] = state[stateOff++]; + } + } + + @Override + protected byte[] engineGenerateSeed(int seedLen) + { + return source.generateSeed(seedLen); + } + + private void generateState() + { + source.nextBytes(state); + + digest.update(seed); + digest.update(state); + + try + { + digest.digest(state, 0, state.length); + } + catch (DigestException e) + { + throw new IllegalStateException("unable to generate nonce data: " + e.getMessage(), e); + } + } + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSASigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSASigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSASigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSASigner.java 2016-10-10 00:10:52.000000000 +0000 @@ -0,0 +1,17 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.PrivateKey; + +import org.bouncycastle.tls.SignatureAlgorithm; + +/** + * Implementation class for generation of the raw DSA signature type using the JCA. + */ +public class JcaTlsDSASigner + extends JcaTlsDSSSigner +{ + public JcaTlsDSASigner(JcaTlsCrypto crypto, PrivateKey privateKey) + { + super(crypto, privateKey, SignatureAlgorithm.dsa, "NoneWithDSA"); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSAVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSAVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSAVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSAVerifier.java 2016-10-10 00:12:59.000000000 +0000 @@ -0,0 +1,62 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.GeneralSecurityException; +import java.security.Signature; +import java.security.interfaces.DSAPublicKey; + +import org.bouncycastle.jcajce.util.JcaJceHelper; +import org.bouncycastle.tls.DigitallySigned; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.crypto.TlsVerifier; + +/** + * Implementation class for the verification of the raw DSA signature type using the JCA. + */ +public class JcaTlsDSAVerifier + implements TlsVerifier +{ + private final JcaJceHelper helper; + private final DSAPublicKey pubKey; + + protected JcaTlsDSAVerifier(DSAPublicKey pubKey, JcaJceHelper helper) + { + if (pubKey == null) + { + throw new IllegalArgumentException("'pubKey' cannot be null"); + } + + this.pubKey = pubKey; + this.helper = helper; + } + + public boolean verifySignature(DigitallySigned signedParams, byte[] hash) + { + SignatureAndHashAlgorithm algorithm = signedParams.getAlgorithm(); + if (algorithm != null && algorithm.getSignature() != SignatureAlgorithm.dsa) + { + throw new IllegalStateException(); + } + + try + { + Signature signer = helper.createSignature("NoneWithDSA"); + + signer.initVerify(pubKey); + if (algorithm == null) + { + // Note: Only use the SHA1 part of the (MD5/SHA1) hash + signer.update(hash, 16, 20); + } + else + { + signer.update(hash, 0, hash.length); + } + return signer.verify(signedParams.getSignature()); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException("unable to process signature: " + e.getMessage(), e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSSSigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSSSigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSSSigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsDSSSigner.java 2016-10-09 23:49:45.000000000 +0000 @@ -0,0 +1,61 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.Signature; + +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.TlsSigner; + +/** + * JCA base class for the signers implementing the two DSA style algorithms from FIPS PUB 186-4: DSA and ECDSA. + */ +public class JcaTlsDSSSigner + implements TlsSigner +{ + private final JcaTlsCrypto crypto; + private final PrivateKey privateKey; + private final short algorithmType; + private final String algorithmName; + + public JcaTlsDSSSigner(JcaTlsCrypto crypto, PrivateKey privateKey, short algorithmType, String algorithmName) + { + this.crypto = crypto; + this.privateKey = privateKey; + this.algorithmType = algorithmType; + this.algorithmName = algorithmName; + } + + public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, byte[] hash) + throws IOException + { + if (algorithm != null && algorithm.getSignature() != algorithmType) + { + throw new IllegalStateException(); + } + + try + { + Signature signer = crypto.getHelper().createSignature(algorithmName); + + signer.initSign(privateKey); + if (algorithm == null) + { + // Note: Only use the SHA1 part of the (MD5/SHA1) hash + signer.update(hash, 16, 20); + } + else + { + signer.update(hash, 0, hash.length); + } + return signer.sign(); + } + catch (GeneralSecurityException e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSASigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSASigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSASigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSASigner.java 2016-10-10 00:10:52.000000000 +0000 @@ -0,0 +1,17 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.PrivateKey; + +import org.bouncycastle.tls.SignatureAlgorithm; + +/** + * Implementation class for generation of the raw ECDSA signature type using the JCA. + */ +public class JcaTlsECDSASigner + extends JcaTlsDSSSigner +{ + public JcaTlsECDSASigner(JcaTlsCrypto crypto, PrivateKey privateKey) + { + super(crypto, privateKey, SignatureAlgorithm.ecdsa, "NoneWithECDSA"); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSAVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSAVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSAVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSAVerifier.java 2016-11-01 20:33:01.000000000 +0000 @@ -0,0 +1,62 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.GeneralSecurityException; +import java.security.Signature; +import java.security.interfaces.ECPublicKey; + +import org.bouncycastle.jcajce.util.JcaJceHelper; +import org.bouncycastle.tls.DigitallySigned; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.crypto.TlsVerifier; + +/** + * Implementation class for the verification of the raw ECDSA signature type using the JCA. + */ +public class JcaTlsECDSAVerifier + implements TlsVerifier +{ + private final JcaJceHelper helper; + private final ECPublicKey pubKey; + + protected JcaTlsECDSAVerifier(ECPublicKey pubKey, JcaJceHelper helper) + { + if (pubKey == null) + { + throw new IllegalArgumentException("'pubKey' cannot be null"); + } + + this.pubKey = pubKey; + this.helper = helper; + } + + public boolean verifySignature(DigitallySigned signedParams, byte[] hash) + { + SignatureAndHashAlgorithm algorithm = signedParams.getAlgorithm(); + if (algorithm != null && algorithm.getSignature() != SignatureAlgorithm.ecdsa) + { + throw new IllegalStateException(); + } + + try + { + Signature signer = helper.createSignature("NoneWithECDSA"); + + signer.initVerify(pubKey); + if (algorithm == null) + { + // Note: Only use the SHA1 part of the (MD5/SHA1) hash + signer.update(hash, 16, 20); + } + else + { + signer.update(hash, 0, hash.length); + } + return signer.verify(signedParams.getSignature()); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException("unable to process signature: " + e.getMessage(), e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsHash.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsHash.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsHash.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsHash.java 2016-10-09 23:55:07.000000000 +0000 @@ -0,0 +1,46 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.MessageDigest; + +import org.bouncycastle.tls.crypto.TlsHash; + +/** + * Wrapper class for providing support methods for a TlsHash based on the JCA MessageDigest class. + */ +public class JcaTlsHash + implements TlsHash +{ + private final MessageDigest digest; + + public JcaTlsHash(MessageDigest digest) + { + this.digest = digest; + } + + public void update(byte[] data, int offSet, int length) + { + digest.update(data, offSet, length); + } + + public byte[] calculateHash() + { + return digest.digest(); + } + + public Object clone() + { + try + { + return new JcaTlsHash((MessageDigest)digest.clone()); + } + catch (CloneNotSupportedException e) + { + throw new UnsupportedOperationException("unable to clone digest"); + } + } + + public void reset() + { + digest.reset(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSASigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSASigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSASigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSASigner.java 2016-11-05 03:42:03.000000000 +0000 @@ -0,0 +1,83 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.Signature; + +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.DigestInfo; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsSigner; + +/** + * Operator supporting the generation of RSA signatures. + */ +public class JcaTlsRSASigner + implements TlsSigner +{ + private final PrivateKey privateKey; + private final JcaTlsCrypto crypto; + + public JcaTlsRSASigner(JcaTlsCrypto crypto, PrivateKey privateKey) + { + this.crypto = crypto; + + if (privateKey == null) + { + throw new IllegalArgumentException("'privateKey' cannot be null"); + } + + this.privateKey = privateKey; + } + + public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, + byte[] hash) throws IOException + { + try + { + Signature signer = crypto.getHelper().createSignature("NoneWithRSA"); + signer.initSign(privateKey, crypto.getSecureRandom()); + if (algorithm != null) + { + if (algorithm.getSignature() != SignatureAlgorithm.rsa) + { + throw new IllegalStateException(); + } + + /* + * RFC 5246 4.7. In RSA signing, the opaque vector contains the signature generated + * using the RSASSA-PKCS1-v1_5 signature scheme defined in [PKCS1]. + */ + try + { + byte[] digInfo = new DigestInfo(new AlgorithmIdentifier(TlsUtils.getOIDForHashAlgorithm(algorithm.getHash()), DERNull.INSTANCE), hash).getEncoded(); + signer.update(digInfo, 0, digInfo.length); + } + catch (IOException e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } + else + { + /* + * RFC 5246 4.7. Note that earlier versions of TLS used a different RSA signature scheme + * that did not include a DigestInfo encoding. + */ + signer.update(hash, 0, hash.length); + } + + return signer.sign(); + } + catch (GeneralSecurityException e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSAVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSAVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSAVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSAVerifier.java 2016-11-05 03:42:03.000000000 +0000 @@ -0,0 +1,84 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.Signature; +import java.security.interfaces.RSAPublicKey; + +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.DigestInfo; +import org.bouncycastle.jcajce.util.JcaJceHelper; +import org.bouncycastle.tls.DigitallySigned; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsVerifier; + +/** + * Operator supporting the verification of RSA signatures. + */ +public class JcaTlsRSAVerifier + implements TlsVerifier +{ + private final JcaJceHelper helper; + protected RSAPublicKey pubKeyRSA; + + public JcaTlsRSAVerifier(RSAPublicKey pubKeyRSA, JcaJceHelper helper) + { + if (pubKeyRSA == null) + { + throw new IllegalArgumentException("'pubKeyRSA' cannot be null"); + } + + this.pubKeyRSA = pubKeyRSA; + this.helper = helper; + } + + public boolean verifySignature(DigitallySigned signedParams, byte[] hash) + { + SignatureAndHashAlgorithm algorithm = signedParams.getAlgorithm(); + + try + { + Signature signer = helper.createSignature("NoneWithRSA"); + signer.initVerify(pubKeyRSA); + if (algorithm != null) + { + if (algorithm.getSignature() != SignatureAlgorithm.rsa) + { + throw new IllegalStateException(); + } + + /* + * RFC 5246 4.7. In RSA signing, the opaque vector contains the signature generated + * using the RSASSA-PKCS1-v1_5 signature scheme defined in [PKCS1]. + */ + + try + { + byte[] digInfo = new DigestInfo(new AlgorithmIdentifier(TlsUtils.getOIDForHashAlgorithm(algorithm.getHash()), DERNull.INSTANCE), hash).getEncoded(); + signer.update(digInfo, 0, digInfo.length); + } + catch (IOException e) + { + e.printStackTrace(); // TODO + } + } + else + { + /* + * RFC 5246 4.7. Note that earlier versions of TLS used a different RSA signature scheme + * that did not include a DigestInfo encoding. + */ + signer.update(hash, 0, hash.length); + } + + return signer.verify(signedParams.getSignature()); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException("unable to process signature: " + e.getMessage(), e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,65 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.GeneralSecurityException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jcajce.spec.AEADParameterSpec; +import org.bouncycastle.tls.crypto.impl.TlsAEADCipherImpl; + +/** + * A basic wrapper for a JCE Cipher class to provide the needed AEAD cipher functionality for TLS. + */ +public class JceAEADCipherImpl + implements TlsAEADCipherImpl +{ + private final int cipherMode; + private final Cipher cipher; + private final String algorithm; + + private SecretKey key; + + public JceAEADCipherImpl(Cipher cipher, String algorithm, boolean isEncrypting) + throws GeneralSecurityException + { + this.cipher = cipher; + this.algorithm = algorithm; + this.cipherMode = (isEncrypting) ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; + } + + public void setKey(byte[] key) + { + this.key = new SecretKeySpec(key, algorithm); + } + + public void init(byte[] nonce, int macSize, byte[] additionalData) + { + try + { + cipher.init(cipherMode, key, new AEADParameterSpec(nonce, macSize * 8, additionalData)); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException(e); + } + } + + public int getOutputSize(int inputLength) + { + return cipher.getOutputSize(inputLength); + } + + public int doFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) + { + try + { + return cipher.doFinal(input, inputOffset, inputLength, output, outputOffset); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException(e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceBlockCipherImpl.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceBlockCipherImpl.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceBlockCipherImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceBlockCipherImpl.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,65 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.GeneralSecurityException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.tls.crypto.impl.TlsBlockCipherImpl; + +/** + * A basic wrapper for a JCE Cipher class to provide the needed block cipher functionality for TLS. + */ +public class JceBlockCipherImpl + implements TlsBlockCipherImpl +{ + private final int cipherMode; + private final Cipher cipher; + private final String algorithm; + + private SecretKey key; + + public JceBlockCipherImpl(Cipher cipher, String algorithm, boolean isEncrypting) + throws GeneralSecurityException + { + this.cipher = cipher; + this.algorithm = algorithm; + this.cipherMode = (isEncrypting) ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; + } + + public void setKey(byte[] key) + { + this.key = new SecretKeySpec(key, algorithm); + } + + public void init(byte[] iv) + { + try + { + cipher.init(cipherMode, key, new IvParameterSpec(iv)); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException(e); + } + } + + public int doFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) + { + try + { + return cipher.doFinal(input, inputOffset, inputLength, output, outputOffset); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException(e); + } + } + + public int getBlockSize() + { + return cipher.getBlockSize(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceBlockCipherWithCBCImplicitIVImpl.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceBlockCipherWithCBCImplicitIVImpl.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceBlockCipherWithCBCImplicitIVImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceBlockCipherWithCBCImplicitIVImpl.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,82 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.GeneralSecurityException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.tls.crypto.impl.TlsBlockCipherImpl; +import org.bouncycastle.util.Arrays; + +/** + * A basic wrapper for a JCE Cipher class to provide the needed block cipher functionality for TLS where the + * cipher requires the IV to be continued between calls. + */ +public class JceBlockCipherWithCBCImplicitIVImpl + implements TlsBlockCipherImpl +{ + private final Cipher cipher; + private final String algorithm; + private final boolean isEncrypting; + + private SecretKey key; + private byte[] nextIV; + + public JceBlockCipherWithCBCImplicitIVImpl(Cipher cipher, String algorithm, boolean isEncrypting) + throws GeneralSecurityException + { + this.cipher = cipher; + this.algorithm = algorithm; + this.isEncrypting = isEncrypting; + } + + public void setKey(byte[] key) + { + this.key = new SecretKeySpec(key, algorithm); + } + + public void init(byte[] iv) + { + if (nextIV != null) + { + throw new IllegalStateException("unexpected reinitialization of an implicit-IV cipher"); + } + + nextIV = iv; + } + + public int doFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) + { + try + { + cipher.init(isEncrypting ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, key, new IvParameterSpec(nextIV)); + + nextIV = null; + + if (!isEncrypting) + { + nextIV = Arrays.copyOfRange(input, inputOffset + inputLength - cipher.getBlockSize(), inputOffset + inputLength); + } + + int len = cipher.doFinal(input, inputOffset, inputLength, output, outputOffset); + + if (isEncrypting) + { + nextIV = Arrays.copyOfRange(output, outputOffset + inputLength - cipher.getBlockSize(), outputOffset + inputLength); + } + + return len; + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException(e); + } + } + + public int getBlockSize() + { + return cipher.getBlockSize(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedAgreement.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedAgreement.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedAgreement.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedAgreement.java 2016-11-05 03:44:19.000000000 +0000 @@ -0,0 +1,93 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.interfaces.ECPrivateKey; + +import javax.crypto.KeyAgreement; +import javax.crypto.interfaces.DHPrivateKey; + +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.TlsCredentialedAgreement; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsSecret; + +/** + * Credentialed class generating agreed secrets from a peer's public key for our end of the TLS connection using the JCE. + */ +public class JceDefaultTlsCredentialedAgreement + implements TlsCredentialedAgreement +{ + private final JcaTlsCrypto crypto; + private final String algorithm; + private final Certificate certificate; + private final PrivateKey privateKey; + + public JceDefaultTlsCredentialedAgreement(JcaTlsCrypto crypto, Certificate certificate, PrivateKey privateKey) + { + if (crypto == null) + { + throw new IllegalArgumentException("'crypto' cannot be null"); + } + if (certificate == null) + { + throw new IllegalArgumentException("'certificate' cannot be null"); + } + if (certificate.isEmpty()) + { + throw new IllegalArgumentException("'certificate' cannot be empty"); + } + if (privateKey == null) + { + throw new IllegalArgumentException("'privateKey' cannot be null"); + } + + this.crypto = crypto; + this.certificate = certificate; + this.privateKey = privateKey; + + if (privateKey instanceof DHPrivateKey) + { + algorithm = "DH"; + } + else if (privateKey instanceof ECPrivateKey) + { + algorithm = "ECDH"; + } + else + { + throw new IllegalArgumentException("'privateKey' type not supported: " + + privateKey.getClass().getName()); + } + } + + public Certificate getCertificate() + { + return certificate; + } + + public TlsSecret generateAgreement(TlsCertificate peerCertificate) + throws IOException + { + try + { + KeyAgreement agreement = crypto.getHelper().createKeyAgreement(algorithm); + + agreement.init(privateKey); + + agreement.doPhase(JcaTlsCertificate.convert(peerCertificate, crypto.getHelper()).getPublicKey(), true); + + /* + * RFC 5246 8.1.2. Leading bytes of Z that contain all zero bits are stripped before it is + * used as the pre_master_secret. We use the convention established by the JSSE to signal this + * by asking for "TlsPremasterSecret". + */ + return new JceTlsSecret(crypto, agreement.generateSecret("TlsPremasterSecret").getEncoded()); + } + catch (GeneralSecurityException e) + { + throw new IOException("unable to perform agreement: " + e.getMessage(), e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java 2016-12-16 22:29:42.000000000 +0000 @@ -0,0 +1,161 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.interfaces.RSAPrivateKey; + +import javax.crypto.Cipher; + +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.TlsCredentialedDecryptor; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.Arrays; + +/** + * Credentialed class decrypting RSA encrypted secrets sent from a peer for our end of the TLS connection using the JCE. + */ +public class JceDefaultTlsCredentialedDecryptor + implements TlsCredentialedDecryptor +{ + protected JcaTlsCrypto crypto; + protected Certificate certificate; + protected PrivateKey privateKey; + + public JceDefaultTlsCredentialedDecryptor(JcaTlsCrypto crypto, Certificate certificate, + PrivateKey privateKey) + { + if (crypto == null) + { + throw new IllegalArgumentException("'crypto' cannot be null"); + } + if (certificate == null) + { + throw new IllegalArgumentException("'certificate' cannot be null"); + } + if (certificate.isEmpty()) + { + throw new IllegalArgumentException("'certificate' cannot be empty"); + } + if (privateKey == null) + { + throw new IllegalArgumentException("'privateKey' cannot be null"); + } + + if (privateKey instanceof RSAPrivateKey || "RSA".equals(privateKey.getAlgorithm())) + { + this.crypto = crypto; + this.certificate = certificate; + this.privateKey = privateKey; + } + else + { + throw new IllegalArgumentException("'privateKey' type not supported: " + + privateKey.getClass().getName()); + } + } + + public Certificate getCertificate() + { + return certificate; + } + + public TlsSecret decrypt(TlsCryptoParameters cryptoParams, byte[] ciphertext) throws IOException + { + // TODO Keep only the decryption itself here - move error handling outside + return safeDecryptPreMasterSecret(cryptoParams, privateKey, ciphertext); + } + + /* + * TODO[tls-ops] Probably need to make RSA encryption/decryption into TlsCrypto functions so + * that users can implement "generic" encryption credentials externally + */ + protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams, PrivateKey rsaServerPrivateKey, + byte[] encryptedPreMasterSecret) + { + SecureRandom secureRandom = crypto.getSecureRandom(); + + /* + * RFC 5246 7.4.7.1. + */ + ProtocolVersion clientVersion = cryptoParams.getClientVersion(); + + // TODO Provide as configuration option? + boolean versionNumberCheckDisabled = false; + + /* + * Generate 48 random bytes we can use as a Pre-Master-Secret, if the + * PKCS1 padding check should fail. + */ + byte[] fallback = new byte[48]; + secureRandom.nextBytes(fallback); + + byte[] M = Arrays.clone(fallback); + try + { + Cipher c; + try + { + c = crypto.getHelper().createCipher("RSA/NONE/PKCS1Padding"); + } + catch (NoSuchAlgorithmException e) + { + c = crypto.getHelper().createCipher("RSA/ECB/PKCS1Padding"); // try old style + } + + c.init(Cipher.DECRYPT_MODE, rsaServerPrivateKey); + + M = c.doFinal(encryptedPreMasterSecret); + } + catch (Exception e) + { + /* + * A TLS server MUST NOT generate an alert if processing an + * RSA-encrypted premaster secret message fails, or the version number is not as + * expected. Instead, it MUST continue the handshake with a randomly generated + * premaster secret. + */ + } + + /* + * If ClientHello.client_version is TLS 1.1 or higher, server implementations MUST + * check the version number [..]. + */ + if (versionNumberCheckDisabled && clientVersion.isEqualOrEarlierVersionOf(ProtocolVersion.TLSv10)) + { + /* + * If the version number is TLS 1.0 or earlier, server + * implementations SHOULD check the version number, but MAY have a + * configuration option to disable the check. + * + * So there is nothing to do here. + */ + } + else + { + /* + * OK, we need to compare the version number in the decrypted Pre-Master-Secret with the + * clientVersion received during the handshake. If they don't match, we replace the + * decrypted Pre-Master-Secret with a random one. + */ + int correct = (clientVersion.getMajorVersion() ^ (M[0] & 0xff)) + | (clientVersion.getMinorVersion() ^ (M[1] & 0xff)); + correct |= correct >> 1; + correct |= correct >> 2; + correct |= correct >> 4; + int mask = ~((correct & 1) - 1); + + /* + * mask will be all bits set to 0xff if the version number differed. + */ + for (int i = 0; i < 48; i++) + { + M[i] = (byte)((M[i] & (~mask)) | (fallback[i] & mask)); + } + } + return crypto.createSecret(M); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceStreamCipherImpl.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceStreamCipherImpl.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceStreamCipherImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceStreamCipherImpl.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,82 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.GeneralSecurityException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.tls.crypto.impl.TlsStreamCipherImpl; + +/** + * A basic wrapper for a JCE Cipher class to provide the needed stream cipher functionality for TLS. + */ +public class JceStreamCipherImpl + implements TlsStreamCipherImpl +{ + private final int cipherMode; + private final Cipher cipher; + private final String baseAlgorithm; + + private SecretKey key; + private boolean hasNoIv; + + public JceStreamCipherImpl(Cipher cipher, String algorithm, boolean isEncrypting) + throws GeneralSecurityException + { + this.cipher = cipher; + this.baseAlgorithm = algorithm; + this.cipherMode = (isEncrypting) ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; + } + + public void setKey(byte[] key) + { + this.key = new SecretKeySpec(key, baseAlgorithm); + } + + public void init(byte[] iv) + { + try + { + if (iv != null) + { + hasNoIv = false; + cipher.init(cipherMode, key, new IvParameterSpec(iv)); + } + else + { + hasNoIv = true; + cipher.init(cipherMode, key); + } + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException(e); + } + } + + public int doFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) + { + try + { + if (hasNoIv) + { + // note: this assumes no internal buffering will take place - fine for BC but with others not so sure.. + int len = cipher.update(input, inputOffset, inputLength, output, outputOffset); + + return len; + } + else + { + int len = cipher.doFinal(input, inputOffset, inputLength, output, outputOffset); + + return len; + } + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException(e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDHDomain.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDHDomain.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDHDomain.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDHDomain.java 2016-10-09 00:47:20.000000000 +0000 @@ -0,0 +1,125 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; + +import javax.crypto.KeyAgreement; +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.DHPublicKeySpec; + +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsDHDomain; +import org.bouncycastle.util.BigIntegers; + +/** + * JCE support class for Diffie-Hellman key pair generation and key agreement over a specified Diffie-Hellman configuration. + */ +public class JceTlsDHDomain + implements TlsDHDomain +{ + protected JcaTlsCrypto crypto; + protected TlsDHConfig dhConfig; + protected DHParameterSpec dhDomain; + + public JceTlsDHDomain(JcaTlsCrypto crypto, TlsDHConfig dhConfig) + { + this.crypto = crypto; + this.dhConfig = dhConfig; + this.dhDomain = getParameters(dhConfig); + } + + public byte[] calculateDHAgreement(DHPublicKey publicKey, DHPrivateKey privateKey) + throws GeneralSecurityException + { + KeyAgreement agreement = crypto.getHelper().createKeyAgreement("DH"); + + agreement.init(privateKey); + + agreement.doPhase(publicKey, true); + + /* + * RFC 5246 8.1.2. Leading bytes of Z that contain all zero bits are stripped before it is + * used as the pre_master_secret. We use the convention established by the JSSE to signal this + * by asking for "TlsPremasterSecret". + */ + return agreement.generateSecret("TlsPremasterSecret").getEncoded(); + } + + public TlsAgreement createDH() + { + return new JceTlsDH(this); + } + + public static BigInteger decodeParameter(byte[] encoding) throws IOException + { + return new BigInteger(1, encoding); + } + + public DHPublicKey decodePublicKey(byte[] encoding) throws IOException + { + try + { + BigInteger y = decodeParameter(encoding); + + // TODO Check RFCs for any validation that could/should be done here + KeyFactory keyFactory = crypto.getHelper().createKeyFactory("DH"); + + return (DHPublicKey)keyFactory.generatePublic(new DHPublicKeySpec(y, dhDomain.getP(), dhDomain.getG())); + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); + } + } + + public byte[] encodeParameter(BigInteger x) throws IOException + { + return BigIntegers.asUnsignedByteArray(x); + } + + public byte[] encodePublicKey(DHPublicKey publicKey) throws IOException + { + return encodeParameter(publicKey.getY()); + } + + public KeyPair generateKeyPair() + { + try + { + KeyPairGenerator keyPairGenerator = crypto.getHelper().createKeyPairGenerator("EC"); + keyPairGenerator.initialize(getParameters(dhConfig), crypto.getSecureRandom()); + return keyPairGenerator.generateKeyPair(); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException("unable to create key pair: " + e.getMessage(), e); + } + } + + public JcaTlsCrypto getCrypto() + { + return crypto; + } + + public DHParameterSpec getParameters(TlsDHConfig dhConfig) + { + // TODO There's a draft RFC for negotiated (named) groups + + BigInteger[] pg = dhConfig.getExplicitPG(); + if (pg != null) + { + return new DHParameterSpec(pg[0], pg[1]); + } + + throw new IllegalStateException("No DH configuration provided"); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDH.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDH.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDH.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDH.java 2016-10-09 00:47:20.000000000 +0000 @@ -0,0 +1,51 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; + +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsSecret; + +/** + * Support class for ephemeral Diffie-Hellman using the JCE. + */ +public class JceTlsDH + implements TlsAgreement +{ + protected JceTlsDHDomain domain; + protected KeyPair localKeyPair; + protected DHPublicKey peerPublicKey; + + public JceTlsDH(JceTlsDHDomain domain) + { + this.domain = domain; + } + + public byte[] generateEphemeral() throws IOException + { + this.localKeyPair = domain.generateKeyPair(); + return domain.encodePublicKey((DHPublicKey)localKeyPair.getPublic()); + } + + public void receivePeerValue(byte[] peerValue) throws IOException + { + this.peerPublicKey = domain.decodePublicKey(peerValue); + } + + public TlsSecret calculateSecret() throws IOException + { + try + { + byte[] data = domain.calculateDHAgreement(peerPublicKey, (DHPrivateKey)localKeyPair.getPrivate()); + return domain.getCrypto().adoptLocalSecret(data); + } + catch (GeneralSecurityException e) + { + throw new IOException("cannot calculate secret", e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDH.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDH.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDH.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDH.java 2016-12-09 00:25:49.000000000 +0000 @@ -0,0 +1,50 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; + +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsSecret; + +/** + * Support class for ephemeral Elliptic Curve Diffie-Hellman using the JCE. + */ +public class JceTlsECDH + implements TlsAgreement +{ + protected JceTlsECDomain domain; + protected KeyPair localKeyPair; + protected ECPublicKey peerPublicKey; + + public JceTlsECDH(JceTlsECDomain domain) + { + this.domain = domain; + } + + public byte[] generateEphemeral() throws IOException + { + this.localKeyPair = domain.generateKeyPair(); + return domain.encodePublicKey((ECPublicKey)localKeyPair.getPublic()); + } + + public void receivePeerValue(byte[] peerValue) throws IOException + { + this.peerPublicKey = domain.decodePublicKey(peerValue); + } + + public TlsSecret calculateSecret() throws IOException + { + try + { + byte[] data = domain.calculateECDHAgreement(peerPublicKey, (ECPrivateKey)localKeyPair.getPrivate()); + return domain.getCrypto().adoptLocalSecret(data); + } + catch (GeneralSecurityException e) + { + throw new IOException("cannot calculate secret", e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java 2016-12-09 00:25:49.000000000 +0000 @@ -0,0 +1,243 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECField; +import java.security.spec.ECFieldF2m; +import java.security.spec.ECFieldFp; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.EllipticCurve; + +import javax.crypto.KeyAgreement; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.NamedCurve; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.tls.crypto.TlsECDomain; + +/** + * EC domain class for generating key pairs and performing key agreement. + */ +public class JceTlsECDomain + implements TlsECDomain +{ + protected JcaTlsCrypto crypto; + protected TlsECConfig ecConfig; + protected AlgorithmParameters ecDomain; + protected ECCurve ecCurve; + + public JceTlsECDomain(JcaTlsCrypto crypto, TlsECConfig ecConfig) + { + this.crypto = crypto; + this.ecConfig = ecConfig; + + init(ecConfig.getNamedCurve()); + } + + public byte[] calculateECDHAgreement(ECPublicKey publicKey, ECPrivateKey privateKey) + throws GeneralSecurityException + { + KeyAgreement agreement = crypto.getHelper().createKeyAgreement("ECDH"); + + agreement.init(privateKey); + + agreement.doPhase(publicKey, true); + + /* + * RFC 4492 5.10. Note that this octet string (Z in IEEE 1363 terminology) as output by + * FE2OSP, the Field Element to Octet String Conversion Primitive, has constant length for + * any given field; leading zeros found in this octet string MUST NOT be truncated. + * + * We use the convention established by the JSSE to signal this by asking for "TlsPremasterSecret". + */ + return agreement.generateSecret("TlsPremasterSecret").getEncoded(); + } + + public TlsAgreement createECDH() + { + return new JceTlsECDH(this); + } + + public ECPoint decodePoint(byte[] encoding) throws IOException + { + return ecCurve.decodePoint(encoding); + } + + public ECPublicKey decodePublicKey(byte[] encoding) throws IOException + { + try + { + KeyFactory keyFact = crypto.getHelper().createKeyFactory("EC"); + ECPoint point = decodePoint(encoding); + ECPublicKeySpec keySpec = new ECPublicKeySpec( + new java.security.spec.ECPoint(point.getAffineXCoord().toBigInteger(), point.getAffineYCoord().toBigInteger()), + ecDomain.getParameterSpec(ECParameterSpec.class)); + // TODO Check RFCs for any validation that could/should be done here + + return (ECPublicKey)keyFact.generatePublic(keySpec); + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); + } + } + + public byte[] encodePoint(ECPoint point) throws IOException + { + return point.getEncoded(ecConfig.getPointCompression()); + } + + public byte[] encodePublicKey(ECPublicKey publicKey) throws IOException + { + java.security.spec.ECPoint w = publicKey.getW(); + + return encodePoint(ecCurve.createPoint(w.getAffineX(), w.getAffineY())); + } + + public KeyPair generateKeyPair() + { + try + { + KeyPairGenerator keyPairGenerator = crypto.getHelper().createKeyPairGenerator("EC"); + keyPairGenerator.initialize(ecDomain.getParameterSpec(ECGenParameterSpec.class), crypto.getSecureRandom()); + return keyPairGenerator.generateKeyPair(); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException("unable to create key pair: " + e.getMessage(), e); + } + } + + public JcaTlsCrypto getCrypto() + { + return crypto; + } + + private void init(int namedCurve) + { + this.ecCurve = null; + this.ecDomain = null; + + String curveName = NamedCurve.getNameOfSpecificCurve(namedCurve); + if (curveName == null) + { + return; + } + + try + { + this.ecDomain = crypto.getHelper().createAlgorithmParameters("EC"); + + this.ecDomain.init(new ECGenParameterSpec(curveName)); + // It's a bit inefficient to do this conversion every time + ECParameterSpec ecSpec = this.ecDomain.getParameterSpec(ECParameterSpec.class); + + this.ecCurve = convertCurve(ecSpec.getCurve(), ecSpec.getOrder(), ecSpec.getCofactor()); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException("unable to create key pair: " + e.getMessage(), e); + } + } + + private static ECCurve convertCurve( + EllipticCurve ec, + BigInteger order, + int cofactor) + { + ECField field = ec.getField(); + BigInteger a = ec.getA(); + BigInteger b = ec.getB(); + + if (field instanceof ECFieldFp) + { + ECCurve.Fp curve = new ECCurve.Fp(((ECFieldFp)field).getP(), a, b, order, BigInteger.valueOf(cofactor)); + + return curve; + } + else + { + ECFieldF2m fieldF2m = (ECFieldF2m)field; + int m = fieldF2m.getM(); + int ks[] = convertMidTerms(fieldF2m.getMidTermsOfReductionPolynomial()); + return new ECCurve.F2m(m, ks[0], ks[1], ks[2], a, b, order, BigInteger.valueOf(cofactor)); + } + } + + private static int[] convertMidTerms( + int[] k) + { + int[] res = new int[3]; + + if (k.length == 1) + { + res[0] = k[0]; + } + else + { + if (k.length != 3) + { + throw new IllegalArgumentException("Only Trinomials and pentanomials supported"); + } + + if (k[0] < k[1] && k[0] < k[2]) + { + res[0] = k[0]; + if (k[1] < k[2]) + { + res[1] = k[1]; + res[2] = k[2]; + } + else + { + res[1] = k[2]; + res[2] = k[1]; + } + } + else if (k[1] < k[2]) + { + res[0] = k[1]; + if (k[0] < k[2]) + { + res[1] = k[0]; + res[2] = k[2]; + } + else + { + res[1] = k[2]; + res[2] = k[0]; + } + } + else + { + res[0] = k[2]; + if (k[0] < k[1]) + { + res[1] = k[0]; + res[2] = k[1]; + } + else + { + res[1] = k[1]; + res[2] = k[0]; + } + } + } + + return res; + } + +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsHMAC.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsHMAC.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsHMAC.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsHMAC.java 2016-10-04 07:14:20.000000000 +0000 @@ -0,0 +1,104 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.tls.crypto.TlsHMAC; + +/** + * Wrapper class for a JCE MAC based on HMAC to provide the necessary operations for TLS. + */ +public class JceTlsHMAC + implements TlsHMAC +{ + private static final Map internalBlockSizes = new HashMap(); + + static + { + internalBlockSizes.put("HmacMD5", 64); + internalBlockSizes.put("HmacSHA1", 64); + internalBlockSizes.put("HmacSHA256", 64); + internalBlockSizes.put("HmacSHA384", 128); + internalBlockSizes.put("HmacSHA512", 128); + } + + private final Mac hmac; + private final String algorithm; + private final Integer internalBlockSize; + + /** + * Base constructor. + * + * @param hmac MAC implementation. + * @param algorithm algorithm name to use for keys and to get the internal block size. + */ + public JceTlsHMAC(Mac hmac, String algorithm) + { + this(hmac, algorithm, getInternalBlockSize(algorithm)); + } + + private static int getInternalBlockSize(String algorithm) + { + if (!internalBlockSizes.containsKey(algorithm)) + { + throw new IllegalArgumentException("HMAC " + algorithm + " unknown"); + } + + return internalBlockSizes.get(algorithm); + } + + /** + * Base constructor specifying the internal block size. + * + * @param hmac MAC implementation. + * @param algorithm algorithm name to use for keys and to get the internal block size. + * @param internalBlockSize internal block size of the message digest underlying the HMAC. + */ + public JceTlsHMAC(Mac hmac, String algorithm, int internalBlockSize) + { + this.hmac = hmac; + this.algorithm = algorithm; + this.internalBlockSize = internalBlockSize; + } + + public void setKey(byte[] key) + { + try + { + hmac.init(new SecretKeySpec(key, algorithm)); + } + catch (InvalidKeyException e) + { + e.printStackTrace(); + } + } + + public void update(byte[] input, int inOff, int length) + { + hmac.update(input, inOff, length); + } + + public byte[] calculateMAC() + { + return hmac.doFinal(); + } + + public int getInternalBlockSize() + { + return internalBlockSize; + } + + public int getMacLength() + { + return hmac.getMacLength(); + } + + public void reset() + { + hmac.reset(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMAC.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMAC.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMAC.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMAC.java 2016-10-04 07:14:20.000000000 +0000 @@ -0,0 +1,57 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.InvalidKeyException; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.tls.crypto.TlsMAC; + +/** + * A basic wrapper for a JCE Mac class to provide the needed functionality for TLS. + */ +public class JceTlsMAC + implements TlsMAC +{ + private final String algorithm; + + private Mac mac; + + public JceTlsMAC(Mac mac, String algorithm) + { + this.mac = mac; + this.algorithm = algorithm; + } + + public void setKey(byte[] key) + { + try + { + mac.init(new SecretKeySpec(key, algorithm)); + } + catch (InvalidKeyException e) + { + e.printStackTrace(); + } + } + + public void update(byte[] input, int inOff, int length) + { + mac.update(input, inOff, length); + } + + public byte[] calculateMAC() + { + return mac.doFinal(); + } + + public int getMacLength() + { + return mac.getMacLength(); + } + + public void reset() + { + mac.reset(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsSecret.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsSecret.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsSecret.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsSecret.java 2016-10-09 00:50:05.000000000 +0000 @@ -0,0 +1,167 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.GeneralSecurityException; +import java.security.MessageDigest; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.tls.PRFAlgorithm; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.tls.crypto.impl.AbstractTlsCrypto; +import org.bouncycastle.tls.crypto.impl.AbstractTlsSecret; +import org.bouncycastle.util.Arrays; + +/** + * JCE support class for handling TLS secrets and deriving key material and other secrets from them. + */ +public class JceTlsSecret + extends AbstractTlsSecret +{ + private final JcaTlsCrypto crypto; + + public JceTlsSecret(JcaTlsCrypto crypto, byte[] data) + { + super(data); + + this.crypto = crypto; + } + + public synchronized TlsSecret deriveSSLKeyBlock(byte[] seed, int length) + { + checkAlive(); + + try + { + int md5Count = (length + MD5_SIZE - 1) / MD5_SIZE; + byte[] md5Buf = prf_SSL(seed, md5Count); + + TlsSecret result = crypto.adoptLocalSecret(Arrays.copyOfRange(md5Buf, 0, length)); + Arrays.fill(md5Buf, (byte)0); + return result; + } + catch (GeneralSecurityException e) + { + throw new RuntimeException(); // TODO: + } + } + + public synchronized TlsSecret deriveSSLMasterSecret(byte[] seed) + { + checkAlive(); + try + { + return crypto.adoptLocalSecret(prf_SSL(seed, 3)); + } + catch (GeneralSecurityException e) + { + throw new RuntimeException(); // TODO: + } + } + + public synchronized TlsSecret deriveUsingPRF(int prfAlgorithm, byte[] labelSeed, int length) + { + checkAlive(); + + try + { + byte[] result = (prfAlgorithm == PRFAlgorithm.tls_prf_legacy) + ? prf_1_0(data, labelSeed, length) + : prf_1_2(crypto.getDigestName(TlsUtils.getHashAlgorithmForPRFAlgorithm(prfAlgorithm)), data, labelSeed, length); + + return crypto.adoptLocalSecret(result); + } + catch (GeneralSecurityException e) + { + throw new IllegalStateException(); // TODO + } + } + + protected AbstractTlsCrypto getCrypto() + { + return crypto; + } + + protected void hmacHash(String digestName, byte[] secret, byte[] seed, byte[] output) + throws GeneralSecurityException + { + String macName = "Hmac" + digestName; + Mac mac = crypto.getHelper().createMac(macName); + mac.init(new SecretKeySpec(secret, macName)); + byte[] a = seed; + int size = mac.getMacLength(); + int iterations = (output.length + size - 1) / size; + byte[] b1 = new byte[mac.getMacLength()]; + byte[] b2 = new byte[mac.getMacLength()]; + for (int i = 0; i < iterations; i++) + { + mac.update(a, 0, a.length); + mac.doFinal(b1, 0); + a = b1; + mac.update(a, 0, a.length); + mac.update(seed, 0, seed.length); + mac.doFinal(b2, 0); + System.arraycopy(b2, 0, output, (size * i), Math.min(size, output.length - (size * i))); + } + } + + protected byte[] prf_SSL(byte[] seed, int md5Count) + throws GeneralSecurityException + { + MessageDigest md5 = crypto.getHelper().createDigest("MD5"); + MessageDigest sha1 = crypto.getHelper().createDigest("SHA-1"); + + int md5Size = md5.getDigestLength(); + byte[] md5Buf = new byte[md5Size * md5Count]; + int md5Pos = 0; + + byte[] sha1Buf = new byte[sha1.getDigestLength()]; + + for (int i = 0; i < md5Count; ++i) + { + byte[] ssl3Const = SSL3_CONST[i]; + + sha1.update(ssl3Const, 0, ssl3Const.length); + sha1.update(data, 0, data.length); + sha1.update(seed, 0, seed.length); + sha1.digest(sha1Buf, 0, sha1Buf.length); + + md5.update(data, 0, data.length); + md5.update(sha1Buf, 0, sha1Buf.length); + md5.digest(md5Buf, md5Pos, md5Size); + + md5Pos += md5Size; + } + + return md5Buf; + } + + protected byte[] prf_1_0(byte[] secret, byte[] labelSeed, int length) + throws GeneralSecurityException + { + int s_half = (secret.length + 1) / 2; + byte[] s1 = new byte[s_half]; + byte[] s2 = new byte[s_half]; + System.arraycopy(secret, 0, s1, 0, s_half); + System.arraycopy(secret, secret.length - s_half, s2, 0, s_half); + + byte[] b1 = new byte[length]; + byte[] b2 = new byte[length]; + hmacHash("MD5", s1, labelSeed, b1); + hmacHash("SHA1", s2, labelSeed, b2); + for (int i = 0; i < length; i++) + { + b1[i] ^= b2[i]; + } + return b1; + } + + protected byte[] prf_1_2(String prfDigest, byte[] secret, byte[] labelSeed, int length) + throws GeneralSecurityException + { + byte[] result = new byte[length]; + hmacHash(prfDigest.replace("-", ""), secret, labelSeed, result); + return result; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Client.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Client.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Client.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Client.java 2016-11-13 04:24:24.000000000 +0000 @@ -0,0 +1,163 @@ +package org.bouncycastle.tls.crypto.impl.jcajce.srp; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.tls.crypto.SRP6Group; +import org.bouncycastle.tls.crypto.TlsHash; + +/** + * Implements the client side SRP-6a protocol. Note that this class is stateful, and therefore NOT threadsafe. + * This implementation of SRP is based on the optimized message sequence put forth by Thomas Wu in the paper + * "SRP-6: Improvements and Refinements to the Secure Remote Password Protocol, 2002" + */ +public class SRP6Client +{ + protected BigInteger N; + protected BigInteger g; + + protected BigInteger a; + protected BigInteger A; + + protected BigInteger B; + + protected BigInteger x; + protected BigInteger u; + protected BigInteger S; + + protected BigInteger M1; + protected BigInteger M2; + protected BigInteger Key; + + protected TlsHash digest; + protected SecureRandom random; + + public SRP6Client() + { + } + + /** + * Initialises the client to begin new authentication attempt + * @param N The safe prime associated with the client's verifier + * @param g The group parameter associated with the client's verifier + * @param digest The digest algorithm associated with the client's verifier + * @param random For key generation + */ + public void init(BigInteger N, BigInteger g, TlsHash digest, SecureRandom random) + { + this.N = N; + this.g = g; + this.digest = digest; + this.random = random; + } + + public void init(SRP6Group group, TlsHash digest, SecureRandom random) + { + init(group.getN(), group.getG(), digest, random); + } + + /** + * Generates client's credentials given the client's salt, identity and password + * @param salt The salt used in the client's verifier. + * @param identity The user's identity (eg. username) + * @param password The user's password + * @return Client's public value to send to server + */ + public BigInteger generateClientCredentials(byte[] salt, byte[] identity, byte[] password) + { + this.x = SRP6Util.calculateX(digest, N, salt, identity, password); + this.a = selectPrivateValue(); + this.A = g.modPow(a, N); + + return A; + } + + /** + * Generates the secret S given the server's credentials + * @param serverB The server's credentials + * @return Client's verification message for the server + * @throws IllegalArgumentException If server's credentials are invalid + */ + public BigInteger calculateSecret(BigInteger serverB) + { + this.B = SRP6Util.validatePublicValue(N, serverB); + this.u = SRP6Util.calculateU(digest, N, A, B); + this.S = calculateS(); + + return S; + } + + protected BigInteger selectPrivateValue() + { + return SRP6Util.generatePrivateValue(N, g, random); + } + + private BigInteger calculateS() + { + BigInteger k = SRP6Util.calculateK(digest, N, g); + BigInteger exp = u.multiply(x).add(a); + BigInteger tmp = g.modPow(x, N).multiply(k).mod(N); + return B.subtract(tmp).mod(N).modPow(exp, N); + } + + /** + * Computes the client evidence message M1 using the previously received values. + * To be called after calculating the secret S. + * @return M1: the client side generated evidence message + * @throws IllegalStateException + */ + public BigInteger calculateClientEvidenceMessage() throws IllegalStateException + { + // Verify pre-requirements + if (this.A == null || this.B == null || this.S == null) + { + throw new IllegalStateException("Impossible to compute M1: " + + "some data are missing from the previous operations (A,B,S)"); + } + // compute the client evidence message 'M1' + this.M1 = SRP6Util.calculateM1(digest, N, A, B, S); + return M1; + } + + /** Authenticates the server evidence message M2 received and saves it only if correct. + * @param serverM2 the server side generated evidence message + * @return A boolean indicating if the server message M2 was the expected one. + * @throws IllegalStateException + */ + public boolean verifyServerEvidenceMessage(BigInteger serverM2) throws IllegalStateException + { + // Verify pre-requirements + if (this.A == null || this.M1 == null || this.S == null) + { + throw new IllegalStateException("Impossible to compute and verify M2: " + + "some data are missing from the previous operations (A,M1,S)"); + } + + // Compute the own server evidence message 'M2' + BigInteger computedM2 = SRP6Util.calculateM2(digest, N, A, M1, S); + if (computedM2.equals(serverM2)) + { + this.M2 = serverM2; + return true; + } + return false; + } + + /** + * Computes the final session key as a result of the SRP successful mutual authentication + * To be called after verifying the server evidence message M2. + * @return Key: the mutually authenticated symmetric session key + * @throws IllegalStateException + */ + public BigInteger calculateSessionKey() throws IllegalStateException + { + // Verify pre-requirements (here we enforce a previous calculation of M1 and M2) + if (this.S == null || this.M1 == null || this.M2 == null) + { + throw new IllegalStateException("Impossible to compute Key: " + + "some data are missing from the previous operations (S,M1,M2)"); + } + this.Key = SRP6Util.calculateKey(digest, N, S); + return Key; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Server.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Server.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Server.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Server.java 2016-11-13 04:24:24.000000000 +0000 @@ -0,0 +1,162 @@ +package org.bouncycastle.tls.crypto.impl.jcajce.srp; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.tls.crypto.SRP6Group; +import org.bouncycastle.tls.crypto.TlsHash; + +/** + * Implements the server side SRP-6a protocol. Note that this class is stateful, and therefore NOT threadsafe. + * This implementation of SRP is based on the optimized message sequence put forth by Thomas Wu in the paper + * "SRP-6: Improvements and Refinements to the Secure Remote Password Protocol, 2002" + */ +public class SRP6Server +{ + protected BigInteger N; + protected BigInteger g; + protected BigInteger v; + + protected SecureRandom random; + protected TlsHash digest; + + protected BigInteger A; + + protected BigInteger b; + protected BigInteger B; + + protected BigInteger u; + protected BigInteger S; + protected BigInteger M1; + protected BigInteger M2; + protected BigInteger Key; + + public SRP6Server() + { + } + + /** + * Initialises the server to accept a new client authentication attempt + * @param N The safe prime associated with the client's verifier + * @param g The group parameter associated with the client's verifier + * @param v The client's verifier + * @param digest The digest algorithm associated with the client's verifier + * @param random For key generation + */ + public void init(BigInteger N, BigInteger g, BigInteger v, TlsHash digest, SecureRandom random) + { + this.N = N; + this.g = g; + this.v = v; + + this.random = random; + this.digest = digest; + } + + public void init(SRP6Group group, BigInteger v, TlsHash digest, SecureRandom random) + { + init(group.getN(), group.getG(), v, digest, random); + } + + /** + * Generates the server's credentials that are to be sent to the client. + * @return The server's public value to the client + */ + public BigInteger generateServerCredentials() + { + BigInteger k = SRP6Util.calculateK(digest, N, g); + this.b = selectPrivateValue(); + this.B = k.multiply(v).mod(N).add(g.modPow(b, N)).mod(N); + + return B; + } + + /** + * Processes the client's credentials. If valid the shared secret is generated and returned. + * @param clientA The client's credentials + * @return A shared secret BigInteger + * @throws IllegalArgumentException If client's credentials are invalid + */ + public BigInteger calculateSecret(BigInteger clientA) throws IllegalArgumentException + { + this.A = SRP6Util.validatePublicValue(N, clientA); + this.u = SRP6Util.calculateU(digest, N, A, B); + this.S = calculateS(); + + return S; + } + + protected BigInteger selectPrivateValue() + { + return SRP6Util.generatePrivateValue(N, g, random); + } + + private BigInteger calculateS() + { + return v.modPow(u, N).multiply(A).mod(N).modPow(b, N); + } + + /** + * Authenticates the received client evidence message M1 and saves it only if correct. + * To be called after calculating the secret S. + * @param clientM1 the client side generated evidence message + * @return A boolean indicating if the client message M1 was the expected one. + * @throws IllegalStateException + */ + public boolean verifyClientEvidenceMessage(BigInteger clientM1) throws IllegalStateException + { + // Verify pre-requirements + if (this.A == null || this.B == null || this.S == null) + { + throw new IllegalStateException("Impossible to compute and verify M1: " + + "some data are missing from the previous operations (A,B,S)"); + } + + // Compute the own client evidence message 'M1' + BigInteger computedM1 = SRP6Util.calculateM1(digest, N, A, B, S); + if (computedM1.equals(clientM1)) + { + this.M1 = clientM1; + return true; + } + return false; + } + + /** + * Computes the server evidence message M2 using the previously verified values. + * To be called after successfully verifying the client evidence message M1. + * @return M2: the server side generated evidence message + * @throws IllegalStateException + */ + public BigInteger calculateServerEvidenceMessage() throws IllegalStateException + { + // Verify pre-requirements + if (this.A == null || this.M1 == null || this.S == null) + { + throw new IllegalStateException("Impossible to compute M2: " + + "some data are missing from the previous operations (A,M1,S)"); + } + + // Compute the server evidence message 'M2' + this.M2 = SRP6Util.calculateM2(digest, N, A, M1, S); + return M2; + } + + /** + * Computes the final session key as a result of the SRP successful mutual authentication + * To be called after calculating the server evidence message M2. + * @return Key: the mutual authenticated symmetric session key + * @throws IllegalStateException + */ + public BigInteger calculateSessionKey() throws IllegalArgumentException + { + // Verify pre-requirements + if (this.S == null || this.M1 == null || this.M2 == null) + { + throw new IllegalStateException("Impossible to compute Key: " + + "some data are missing from the previous operations (S,M1,M2)"); + } + this.Key = SRP6Util.calculateKey(digest, N, S); + return Key; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Util.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Util.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Util.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6Util.java 2016-11-22 03:23:43.000000000 +0000 @@ -0,0 +1,146 @@ +package org.bouncycastle.tls.crypto.impl.jcajce.srp; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.tls.crypto.TlsHash; +import org.bouncycastle.util.BigIntegers; + +class SRP6Util +{ + private static final byte[] colon = new byte[] { (byte)':' }; + + private static BigInteger ZERO = BigInteger.valueOf(0); + private static BigInteger ONE = BigInteger.valueOf(1); + + public static BigInteger calculateK(TlsHash digest, BigInteger N, BigInteger g) + { + return hashPaddedPair(digest, N, N, g); + } + + public static BigInteger calculateU(TlsHash digest, BigInteger N, BigInteger A, BigInteger B) + { + return hashPaddedPair(digest, N, A, B); + } + + public static BigInteger calculateX(TlsHash digest, BigInteger N, byte[] salt, byte[] identity, byte[] password) + { + digest.update(identity, 0, identity.length); + digest.update(colon, 0, 1); + digest.update(password, 0, password.length); + + byte[] output = digest.calculateHash(); + + digest.update(salt, 0, salt.length); + digest.update(output, 0, output.length); + + return new BigInteger(1, digest.calculateHash()); + } + + public static BigInteger generatePrivateValue(BigInteger N, BigInteger g, SecureRandom random) + { + int minBits = Math.min(256, N.bitLength() / 2); + BigInteger min = ONE.shiftLeft(minBits - 1); + BigInteger max = N.subtract(ONE); + + return BigIntegers.createRandomInRange(min, max, random); + } + + public static BigInteger validatePublicValue(BigInteger N, BigInteger val) + throws IllegalArgumentException + { + val = val.mod(N); + + // Check that val % N != 0 + if (val.equals(ZERO)) + { + throw new IllegalArgumentException("Invalid public value: 0"); + } + + return val; + } + + /** + * Computes the client evidence message (M1) according to the standard routine: + * M1 = H( A | B | S ) + * @param digest The Digest used as the hashing function H + * @param N Modulus used to get the pad length + * @param A The public client value + * @param B The public server value + * @param S The secret calculated by both sides + * @return M1 The calculated client evidence message + */ + public static BigInteger calculateM1(TlsHash digest, BigInteger N, BigInteger A, BigInteger B, BigInteger S) { + BigInteger M1 = hashPaddedTriplet(digest,N,A,B,S); + return M1; + } + + /** + * Computes the server evidence message (M2) according to the standard routine: + * M2 = H( A | M1 | S ) + * @param digest The Digest used as the hashing function H + * @param N Modulus used to get the pad length + * @param A The public client value + * @param M1 The client evidence message + * @param S The secret calculated by both sides + * @return M2 The calculated server evidence message + */ + public static BigInteger calculateM2(TlsHash digest, BigInteger N, BigInteger A, BigInteger M1, BigInteger S){ + BigInteger M2 = hashPaddedTriplet(digest,N,A,M1,S); + return M2; + } + + /** + * Computes the final Key according to the standard routine: Key = H(S) + * @param digest The Digest used as the hashing function H + * @param N Modulus used to get the pad length + * @param S The secret calculated by both sides + * @return the final Key value. + */ + public static BigInteger calculateKey(TlsHash digest, BigInteger N, BigInteger S) { + int padLength = (N.bitLength() + 7) / 8; + byte[] _S = getPadded(S,padLength); + digest.update(_S, 0, _S.length); + + return new BigInteger(1, digest.calculateHash()); + } + + private static BigInteger hashPaddedTriplet(TlsHash digest, BigInteger N, BigInteger n1, BigInteger n2, BigInteger n3){ + int padLength = (N.bitLength() + 7) / 8; + + byte[] n1_bytes = getPadded(n1, padLength); + byte[] n2_bytes = getPadded(n2, padLength); + byte[] n3_bytes = getPadded(n3, padLength); + + digest.update(n1_bytes, 0, n1_bytes.length); + digest.update(n2_bytes, 0, n2_bytes.length); + digest.update(n3_bytes, 0, n3_bytes.length); + + return new BigInteger(1, digest.calculateHash()); + } + + private static BigInteger hashPaddedPair(TlsHash digest, BigInteger N, BigInteger n1, BigInteger n2) + { + int padLength = (N.bitLength() + 7) / 8; + + byte[] n1_bytes = getPadded(n1, padLength); + byte[] n2_bytes = getPadded(n2, padLength); + + digest.update(n1_bytes, 0, n1_bytes.length); + digest.update(n2_bytes, 0, n2_bytes.length); + + return new BigInteger(1, digest.calculateHash()); + } + + private static byte[] getPadded(BigInteger n, int length) + { + byte[] bs = BigIntegers.asUnsignedByteArray(n); + if (bs.length < length) + { + byte[] tmp = new byte[length]; + System.arraycopy(bs, 0, tmp, length - bs.length, bs.length); + bs = tmp; + } + return bs; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6VerifierGenerator.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6VerifierGenerator.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6VerifierGenerator.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/srp/SRP6VerifierGenerator.java 2016-11-13 04:13:21.000000000 +0000 @@ -0,0 +1,55 @@ +package org.bouncycastle.tls.crypto.impl.jcajce.srp; + +import java.math.BigInteger; + +import org.bouncycastle.tls.crypto.SRP6Group; +import org.bouncycastle.tls.crypto.TlsHash; + +/** + * Generates new SRP verifier for user + */ +public class SRP6VerifierGenerator +{ + protected BigInteger N; + protected BigInteger g; + protected TlsHash digest; + + public SRP6VerifierGenerator() + { + } + + /** + * Initialises generator to create new verifiers + * @param N The safe prime to use (see DHParametersGenerator) + * @param g The group parameter to use (see DHParametersGenerator) + * @param digest The digest to use. The same digest type will need to be used later for the actual authentication + * attempt. Also note that the final session key size is dependent on the chosen digest. + */ + public void init(BigInteger N, BigInteger g, TlsHash digest) + { + this.N = N; + this.g = g; + this.digest = digest; + } + + public void init(SRP6Group group, TlsHash digest) + { + this.N = group.getN(); + this.g = group.getG(); + this.digest = digest; + } + + /** + * Creates a new SRP verifier + * @param salt The salt to use, generally should be large and random + * @param identity The user's identifying information (eg. username) + * @param password The user's password + * @return A new verifier for use in future SRP authentication + */ + public BigInteger generateVerifier(byte[] salt, byte[] identity, byte[] password) + { + BigInteger x = SRP6Util.calculateX(digest, N, salt, identity, password); + + return g.modPow(x, N); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipherImpl.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipherImpl.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipherImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipherImpl.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,49 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +/** + * Base interface for services supporting AEAD encryption/decryption. + */ +public interface TlsAEADCipherImpl +{ + /** + * Set the key to be used by the AEAD cipher implementation supporting this service. + * + * @param key the AEAD cipher key. + */ + void setKey(byte[] key) throws IOException; + + /** + * Initialise the parameters for the AEAD operator. + * + * @param nonce the nonce. + * @param macSize MAC size in bytes. + * @param additionalData any additional data to be included in the MAC calculation. + * @throws IOException if the parameters are inappropriate. + */ + void init(byte[] nonce, int macSize, byte[] additionalData) throws IOException; + + /** + * Return the maximum size of the output for input of inputLength bytes. + * + * @param inputLength the length (in bytes) of the proposed input. + * @return the maximum size of the output. + */ + int getOutputSize(int inputLength); + + /** + * Perform the cipher encryption/decryption returning the output in output. + *

      + * Note: we have to use doFinal() here as it is the only way to guarantee output from the underlying cipher. + *

      + * @param input array holding input data to the cipher. + * @param inputOffset offset into input array data starts at. + * @param inputLength length of the input data in the array. + * @param output array to hold the cipher output. + * @param outputOffset offset into output array to start saving output. + * @return the amount of data written to output. + * @throws IOException in case of failure. + */ + int doFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipher.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipher.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipher.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipher.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,246 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.util.Arrays; + +/** + * A generic TLS 1.2 AEAD cipher. + */ +public class TlsAEADCipher + implements TlsCipher +{ + // TODO[draft-zauner-tls-aes-ocb-04] Apply data volume limit described in section 8.4 + + public static final int NONCE_RFC5288 = 1; + public static final int NONCE_RFC7905 = 2; + + protected TlsCryptoParameters context; + protected int macSize; + // TODO SecurityParameters.record_iv_length + protected int record_iv_length; + + protected TlsAEADCipherImpl encryptor; + protected TlsAEADCipherImpl decryptor; + + protected byte[] encryptImplicitNonce, decryptImplicitNonce; + + protected int nonceMode; + + public TlsAEADCipher(TlsCryptoParameters context, TlsAEADCipherImpl encryptor, TlsAEADCipherImpl decryptor, + int cipherKeySize, int macSize) throws IOException + { + this(context, encryptor, decryptor, cipherKeySize, macSize, NONCE_RFC5288); + } + + public TlsAEADCipher(TlsCryptoParameters context, TlsAEADCipherImpl encryptor, TlsAEADCipherImpl decryptor, + int cipherKeySize, int macSize, int nonceMode) throws IOException + { + if (!TlsImplUtils.isTLSv12(context)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.nonceMode = nonceMode; + + // TODO SecurityParameters.fixed_iv_length + int fixed_iv_length; + + switch (nonceMode) + { + case NONCE_RFC5288: + fixed_iv_length = 4; + this.record_iv_length = 8; + break; + case NONCE_RFC7905: + fixed_iv_length = 12; + this.record_iv_length = 0; + break; + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.context = context; + this.macSize = macSize; + + int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length); + + byte[] key_block = TlsImplUtils.calculateKeyBlock(context, key_block_size); + + int offset = 0; + + byte[] client_write_key = Arrays.copyOfRange(key_block, offset, offset + cipherKeySize); + offset += cipherKeySize; + byte[] server_write_key = Arrays.copyOfRange(key_block, offset, offset + cipherKeySize); + offset += cipherKeySize; + byte[] client_write_IV = Arrays.copyOfRange(key_block, offset, offset + fixed_iv_length); + offset += fixed_iv_length; + byte[] server_write_IV = Arrays.copyOfRange(key_block, offset, offset + fixed_iv_length); + offset += fixed_iv_length; + + if (offset != key_block_size) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.encryptor = encryptor; + this.decryptor = decryptor; + if (context.isServer()) + { + this.encryptImplicitNonce = server_write_IV; + this.decryptImplicitNonce = client_write_IV; + encryptor.setKey(server_write_key); + decryptor.setKey(client_write_key); + } + else + { + this.encryptImplicitNonce = client_write_IV; + this.decryptImplicitNonce = server_write_IV; + encryptor.setKey(client_write_key); + decryptor.setKey(server_write_key); + } + + byte[] dummyNonce = new byte[fixed_iv_length + record_iv_length]; + + this.encryptor.init(dummyNonce, macSize, null); + this.decryptor.init(dummyNonce, macSize, null); + } + + public int getPlaintextLimit(int ciphertextLimit) + { + // TODO We ought to be able to ask the decryptCipher (independently of it's current state!) + return ciphertextLimit - macSize - record_iv_length; + } + + public byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len) + throws IOException + { + byte[] nonce = new byte[encryptImplicitNonce.length + record_iv_length]; + + switch (nonceMode) + { + case NONCE_RFC5288: + System.arraycopy(encryptImplicitNonce, 0, nonce, 0, encryptImplicitNonce.length); + // RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number. + TlsUtils.writeUint64(seqNo, nonce, encryptImplicitNonce.length); + break; + case NONCE_RFC7905: + TlsUtils.writeUint64(seqNo, nonce, nonce.length - 8); + for (int i = 0; i < encryptImplicitNonce.length; ++i) + { + nonce[i] ^= encryptImplicitNonce[i]; + } + break; + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + int plaintextOffset = offset; + int plaintextLength = len; + int ciphertextLength = encryptor.getOutputSize(plaintextLength); + + byte[] output = new byte[record_iv_length + ciphertextLength]; + if (record_iv_length != 0) + { + System.arraycopy(nonce, nonce.length - record_iv_length, output, 0, record_iv_length); + } + int outputPos = record_iv_length; + + byte[] additionalData = getAdditionalData(seqNo, type, plaintextLength); + + try + { + encryptor.init(nonce, macSize, additionalData); + outputPos += encryptor.doFinal(plaintext, plaintextOffset, plaintextLength, output, outputPos); + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + + if (outputPos != output.length) + { + // NOTE: Existing AEAD cipher implementations all give exact output lengths + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + return output; + } + + public byte[] decodeCiphertext(long seqNo, short type, byte[] ciphertext, int offset, int len) + throws IOException + { + if (getPlaintextLimit(len) < 0) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + byte[] nonce = new byte[decryptImplicitNonce.length + record_iv_length]; + + switch (nonceMode) + { + case NONCE_RFC5288: + System.arraycopy(decryptImplicitNonce, 0, nonce, 0, decryptImplicitNonce.length); + System.arraycopy(ciphertext, offset, nonce, nonce.length - record_iv_length, record_iv_length); + break; + case NONCE_RFC7905: + TlsUtils.writeUint64(seqNo, nonce, nonce.length - 8); + for (int i = 0; i < decryptImplicitNonce.length; ++i) + { + nonce[i] ^= decryptImplicitNonce[i]; + } + break; + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + int ciphertextOffset = offset + record_iv_length; + int ciphertextLength = len - record_iv_length; + int plaintextLength = decryptor.getOutputSize(ciphertextLength); + + byte[] output = new byte[plaintextLength]; + int outputPos = 0; + + byte[] additionalData = getAdditionalData(seqNo, type, plaintextLength); + + try + { + decryptor.init(nonce, macSize, additionalData); + outputPos += decryptor.doFinal(ciphertext, ciphertextOffset, ciphertextLength, output, outputPos); + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.bad_record_mac, e); + } + + if (outputPos != output.length) + { + // NOTE: Existing AEAD cipher implementations all give exact output lengths + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + return output; + } + + protected byte[] getAdditionalData(long seqNo, short type, int len) + throws IOException + { + /* + * additional_data = seq_num + TLSCompressed.type + TLSCompressed.version + + * TLSCompressed.length + */ + + byte[] additional_data = new byte[13]; + TlsUtils.writeUint64(seqNo, additional_data, 0); + TlsUtils.writeUint8(type, additional_data, 8); + TlsUtils.writeVersion(context.getServerVersion(), additional_data, 9); + TlsUtils.writeUint16(len, additional_data, 11); + + return additional_data; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipherImpl.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipherImpl.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipherImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipherImpl.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,46 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +/** + * Interface for block cipher services. + */ +public interface TlsBlockCipherImpl +{ + /** + * Set the key to be used by the block cipher implementation supporting this service. + * + * @param key the block cipher key. + */ + void setKey(byte[] key) throws IOException; + + /** + * Initialise the parameters for operator. + * + * @param iv the initialization vector. + * @throws IOException if the parameters are inappropriate. + */ + void init(byte[] iv) throws IOException; + + /** + * Perform the cipher encryption/decryption returning the output in output. + *

      + * Note: we have to use doFinal() here as it is the only way to guarantee output from the underlying cipher. + *

      + * @param input array holding input data to the cipher. + * @param inputOffset offset into input array data starts at. + * @param inputLength length of the input data in the array. + * @param output array to hold the cipher output. + * @param outputOffset offset into output array to start saving output. + * @return the amount of data written to output. + * @throws IOException in case of failure. + */ + int doFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) throws IOException; + + /** + * Return the blocksize (in bytes) of the underlying block cipher. + * + * @return the cipher's blocksize. + */ + int getBlockSize(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipher.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipher.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipher.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipher.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,381 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; +import java.security.SecureRandom; + +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsHMAC; +import org.bouncycastle.util.Arrays; + +/** + * A generic TLS 1.0-1.2 / SSLv3 block cipher. This can be used for AES or 3DES for example. + */ +public class TlsBlockCipher + implements TlsCipher +{ + protected TlsCryptoParameters cryptoParams; + private final TlsCrypto crypto; + protected byte[] randomData; + protected boolean useExplicitIV; + protected boolean encryptThenMAC; + + protected TlsBlockCipherImpl encryptCipher; + protected TlsBlockCipherImpl decryptCipher; + + protected TlsSuiteMac writeMac; + protected TlsSuiteMac readMac; + + public TlsBlockCipher(TlsCrypto crypto, TlsCryptoParameters cryptoParams, TlsBlockCipherImpl encryptCipher, TlsBlockCipherImpl decryptCipher, + TlsHMAC writeMac, TlsHMAC readMac, int cipherKeySize) + throws IOException + { + this.cryptoParams = cryptoParams; + this.crypto = crypto; + this.randomData = crypto.createNonce(256); + + this.useExplicitIV = TlsImplUtils.isTLSv11(cryptoParams); + this.encryptThenMAC = cryptoParams.getSecurityParameters().isEncryptThenMAC(); + + int key_block_size = (2 * cipherKeySize) + writeMac.getMacLength() + readMac.getMacLength(); + + // From TLS 1.1 onwards, block ciphers don't need client_write_IV + if (!useExplicitIV) + { + key_block_size += encryptCipher.getBlockSize() + decryptCipher.getBlockSize(); + } + + byte[] key_block = TlsImplUtils.calculateKeyBlock(cryptoParams, key_block_size); + + int offset = 0; + + byte[] clientMacKey = Arrays.copyOfRange(key_block, offset, offset + writeMac.getMacLength()); + offset += clientMacKey.length; + byte[] serverMacKey = Arrays.copyOfRange(key_block, offset, offset + writeMac.getMacLength()); + offset += serverMacKey.length; + + byte[] client_write_key = Arrays.copyOfRange(key_block, offset, offset + cipherKeySize); + offset += cipherKeySize; + byte[] server_write_key = Arrays.copyOfRange(key_block, offset, offset + cipherKeySize); + offset += cipherKeySize; + + byte[] server_IV, client_IV; + + if (useExplicitIV) + { + client_IV = new byte[encryptCipher.getBlockSize()]; + server_IV = new byte[encryptCipher.getBlockSize()]; + } + else + { + client_IV = Arrays.copyOfRange(key_block, offset, offset + encryptCipher.getBlockSize()); + offset += encryptCipher.getBlockSize(); + server_IV = Arrays.copyOfRange(key_block, offset, offset + encryptCipher.getBlockSize()); + offset += encryptCipher.getBlockSize(); + } + + if (offset != key_block_size) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.readMac = new TlsSuiteHMac(cryptoParams, readMac); + this.writeMac = new TlsSuiteHMac(cryptoParams, writeMac); + this.encryptCipher = encryptCipher; + this.decryptCipher = decryptCipher; + + if (cryptoParams.isServer()) + { + this.writeMac.setKey(serverMacKey); + this.readMac.setKey(clientMacKey); + + this.encryptCipher.setKey(server_write_key); + this.decryptCipher.setKey(client_write_key); + this.encryptCipher.init(server_IV); + this.decryptCipher.init(client_IV); + } + else + { + this.writeMac.setKey(clientMacKey); + this.readMac.setKey(serverMacKey); + + this.encryptCipher.setKey(client_write_key); + this.decryptCipher.setKey(server_write_key); + this.encryptCipher.init(client_IV); + this.decryptCipher.init(server_IV); + } + } + + public int getPlaintextLimit(int ciphertextLimit) + { + int blockSize = encryptCipher.getBlockSize(); + int macSize = writeMac.getSize(); + + int plaintextLimit = ciphertextLimit; + + // An explicit IV consumes 1 block + if (useExplicitIV) + { + plaintextLimit -= blockSize; + } + + // Leave room for the MAC, and require block-alignment + if (encryptThenMAC) + { + plaintextLimit -= macSize; + plaintextLimit -= plaintextLimit % blockSize; + } + else + { + plaintextLimit -= plaintextLimit % blockSize; + plaintextLimit -= macSize; + } + + // Minimum 1 byte of padding + --plaintextLimit; + + return plaintextLimit; + } + + public byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len) + throws IOException + { + int blockSize = encryptCipher.getBlockSize(); + int macSize = writeMac.getSize(); + + ProtocolVersion version = cryptoParams.getServerVersion(); + + int enc_input_length = len; + if (!encryptThenMAC) + { + enc_input_length += macSize; + } + + int padding_length = blockSize - 1 - (enc_input_length % blockSize); + + // TODO[DTLS] Consider supporting in DTLS (without exceeding send limit though) + if (!version.isDTLS() && !version.isSSL()) + { + // Add a random number of extra blocks worth of padding + int maxExtraPadBlocks = (255 - padding_length) / blockSize; + int actualExtraPadBlocks = chooseExtraPadBlocks(crypto.getSecureRandom(), maxExtraPadBlocks); + padding_length += actualExtraPadBlocks * blockSize; + } + + int totalSize = len + macSize + padding_length + 1; + if (useExplicitIV) + { + totalSize += blockSize; + } + + byte[] outBuf = new byte[totalSize]; + int outOff = 0; + + if (useExplicitIV) + { + byte[] explicitIV = crypto.createNonce(blockSize); + + encryptCipher.init(explicitIV); + + System.arraycopy(explicitIV, 0, outBuf, outOff, blockSize); + outOff += blockSize; + } + + int blocks_start = outOff; + + System.arraycopy(plaintext, offset, outBuf, outOff, len); + outOff += len; + + if (!encryptThenMAC) + { + byte[] mac = writeMac.calculateMac(seqNo, type, plaintext, offset, len); + System.arraycopy(mac, 0, outBuf, outOff, mac.length); + outOff += mac.length; + } + + for (int i = 0; i <= padding_length; i++) + { + outBuf[outOff++] = (byte)padding_length; + } + + encryptCipher.doFinal(outBuf, blocks_start, outOff - blocks_start, outBuf, blocks_start); + + if (encryptThenMAC) + { + byte[] mac = writeMac.calculateMac(seqNo, type, outBuf, 0, outOff); + System.arraycopy(mac, 0, outBuf, outOff, mac.length); + outOff += mac.length; + } + +// assert outBuf.length == outOff; + return outBuf; + } + + public byte[] decodeCiphertext(long seqNo, short type, byte[] ciphertext, int offset, int len) + throws IOException + { + int blockSize = decryptCipher.getBlockSize(); + int macSize = readMac.getSize(); + + int minLen = blockSize; + if (encryptThenMAC) + { + minLen += macSize; + } + else + { + minLen = Math.max(minLen, macSize + 1); + } + + if (useExplicitIV) + { + minLen += blockSize; + } + + if (len < minLen) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + int blocks_length = len; + if (encryptThenMAC) + { + blocks_length -= macSize; + } + + if (blocks_length % blockSize != 0) + { + throw new TlsFatalAlert(AlertDescription.decryption_failed); + } + + if (encryptThenMAC) + { + int end = offset + len; + byte[] receivedMac = Arrays.copyOfRange(ciphertext, end - macSize, end); + byte[] calculatedMac = readMac.calculateMac(seqNo, type, ciphertext, offset, len - macSize); + + boolean badMac = !Arrays.constantTimeAreEqual(calculatedMac, receivedMac); + if (badMac) + { + /* + * RFC 7366 3. The MAC SHALL be evaluated before any further processing such as + * decryption is performed, and if the MAC verification fails, then processing SHALL + * terminate immediately. For TLS, a fatal bad_record_mac MUST be generated [2]. For + * DTLS, the record MUST be discarded, and a fatal bad_record_mac MAY be generated + * [4]. This immediate response to a bad MAC eliminates any timing channels that may + * be available through the use of manipulated packet data. + */ + throw new TlsFatalAlert(AlertDescription.bad_record_mac); + } + } + + if (useExplicitIV) + { + decryptCipher.init(Arrays.copyOfRange(ciphertext, offset, offset + blockSize)); + + offset += blockSize; + blocks_length -= blockSize; + } + + decryptCipher.doFinal(ciphertext, offset, blocks_length, ciphertext, offset); + + // If there's anything wrong with the padding, this will return zero + int totalPad = checkPaddingConstantTime(ciphertext, offset, blocks_length, blockSize, encryptThenMAC ? 0 : macSize); + boolean badMac = (totalPad == 0); + + int dec_output_length = blocks_length - totalPad; + + if (!encryptThenMAC) + { + dec_output_length -= macSize; + int macInputLen = dec_output_length; + int macOff = offset + macInputLen; + byte[] receivedMac = Arrays.copyOfRange(ciphertext, macOff, macOff + macSize); + byte[] calculatedMac = readMac.calculateMacConstantTime(seqNo, type, ciphertext, offset, macInputLen, + blocks_length - macSize, randomData); + + badMac |= !Arrays.constantTimeAreEqual(calculatedMac, receivedMac); + } + + if (badMac) + { + throw new TlsFatalAlert(AlertDescription.bad_record_mac); + } + + return Arrays.copyOfRange(ciphertext, offset, offset + dec_output_length); + } + + protected int checkPaddingConstantTime(byte[] buf, int off, int len, int blockSize, int macSize) + { + int end = off + len; + byte lastByte = buf[end - 1]; + int padlen = lastByte & 0xff; + int totalPad = padlen + 1; + + int dummyIndex = 0; + byte padDiff = 0; + + if ((TlsImplUtils.isSSL(cryptoParams) && totalPad > blockSize) || (macSize + totalPad > len)) + { + totalPad = 0; + } + else + { + int padPos = end - totalPad; + do + { + padDiff |= (buf[padPos++] ^ lastByte); + } + while (padPos < end); + + dummyIndex = totalPad; + + if (padDiff != 0) + { + totalPad = 0; + } + } + + // Run some extra dummy checks so the number of checks is always constant + { + byte[] dummyPad = randomData; + while (dummyIndex < 256) + { + padDiff |= (dummyPad[dummyIndex++] ^ lastByte); + } + // Ensure the above loop is not eliminated + dummyPad[0] ^= padDiff; + } + + return totalPad; + } + + protected int chooseExtraPadBlocks(SecureRandom r, int max) + { + // return r.nextInt(max + 1); + + int x = r.nextInt(); + int n = lowestBitSet(x); + return Math.min(n, max); + } + + protected int lowestBitSet(int x) + { + if (x == 0) + { + return 32; + } + + int n = 0; + while ((x & 1) == 0) + { + ++n; + x >>= 1; + } + return n; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsEncryptor.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsEncryptor.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsEncryptor.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsEncryptor.java 2016-10-08 00:27:24.000000000 +0000 @@ -0,0 +1,21 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +/** + * Base interface for an encryptor based on a public key. + */ +public interface TlsEncryptor +{ + /** + * Encrypt data from the passed in input array. + * + * @param input byte array containing the input data. + * @param inOff offset into input where the data starts. + * @param length the length of the data to encrypt. + * @return the encrypted data. + * @throws IOException in case of a processing error. + */ + byte[] encrypt(byte[] input, int inOff, int length) + throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsImplUtils.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsImplUtils.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsImplUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsImplUtils.java 2016-10-05 03:54:00.000000000 +0000 @@ -0,0 +1,71 @@ +package org.bouncycastle.tls.crypto.impl; + +import org.bouncycastle.tls.ExporterLabel; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SecurityParameters; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +/** + * Useful utility methods. + */ +public class TlsImplUtils +{ + public static boolean isSSL(TlsCryptoParameters cryptoParams) + { + return cryptoParams.getServerVersion().isSSL(); + } + + public static boolean isTLSv11(ProtocolVersion version) + { + return ProtocolVersion.TLSv11.isEqualOrEarlierVersionOf(version.getEquivalentTLSVersion()); + } + + public static boolean isTLSv11(TlsCryptoParameters cryptoParams) + { + return isTLSv11(cryptoParams.getServerVersion()); + } + + public static boolean isTLSv12(ProtocolVersion version) + { + return ProtocolVersion.TLSv12.isEqualOrEarlierVersionOf(version.getEquivalentTLSVersion()); + } + + public static boolean isTLSv12(TlsCryptoParameters cryptoParams) + { + return isTLSv12(cryptoParams.getServerVersion()); + } + + public static byte[] calculateKeyBlock(TlsCryptoParameters cryptoParams, int length) + { + SecurityParameters securityParameters = cryptoParams.getSecurityParameters(); + TlsSecret master_secret = securityParameters.getMasterSecret(); + byte[] seed = Arrays.concatenate(securityParameters.getServerRandom(), securityParameters.getClientRandom()); + + if (isSSL(cryptoParams)) + { + return master_secret.deriveSSLKeyBlock(seed, length).extract(); + } + + return PRF(cryptoParams, master_secret, ExporterLabel.key_expansion, seed, length).extract(); + } + + public static TlsSecret PRF(TlsCryptoParameters cryptoParams, TlsSecret secret, String asciiLabel, byte[] seed, int length) + { + ProtocolVersion version = cryptoParams.getServerVersion(); + + if (version.isSSL()) + { + throw new IllegalStateException("No PRF available for SSLv3 session"); + } + + byte[] label = Strings.toByteArray(asciiLabel); + byte[] labelSeed = Arrays.concatenate(label, seed); + + int prfAlgorithm = cryptoParams.getSecurityParameters().getPrfAlgorithm(); + + return secret.deriveUsingPRF(prfAlgorithm, labelSeed, length); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsNullCipher.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsNullCipher.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsNullCipher.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsNullCipher.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,98 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsHMAC; +import org.bouncycastle.util.Arrays; + +/** + * The NULL cipher. + */ +public class TlsNullCipher + implements TlsCipher +{ + protected TlsCryptoParameters cryptoParameters; + + protected TlsSuiteHMac writeMac; + protected TlsSuiteHMac readMac; + + public TlsNullCipher(TlsCryptoParameters cryptoParameters, TlsHMAC clientMac, TlsHMAC serverMac) + throws IOException + { + this.cryptoParameters = cryptoParameters; + + int key_block_size = clientMac.getMacLength() + serverMac.getMacLength(); + byte[] key_block = TlsImplUtils.calculateKeyBlock(cryptoParameters, key_block_size); + + int offset = 0; + + byte[] clientMacKey = Arrays.copyOfRange(key_block, offset, offset + clientMac.getMacLength()); + offset += clientMacKey.length; + byte[] serverMacKey = Arrays.copyOfRange(key_block, offset, offset + serverMac.getMacLength()); + offset += serverMacKey.length; + + if (offset != key_block_size) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + if (cryptoParameters.isServer()) + { + writeMac = new TlsSuiteHMac(cryptoParameters, serverMac); + readMac = new TlsSuiteHMac(cryptoParameters, clientMac); + + writeMac.setKey(serverMacKey); + readMac.setKey(clientMacKey); + + } + else + { + writeMac = new TlsSuiteHMac(cryptoParameters, clientMac); + readMac = new TlsSuiteHMac(cryptoParameters, serverMac); + + writeMac.setKey(clientMacKey); + readMac.setKey(serverMacKey); + } + } + + public int getPlaintextLimit(int ciphertextLimit) + { + return ciphertextLimit - writeMac.getSize(); + } + + public byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len) + throws IOException + { + byte[] mac = writeMac.calculateMac(seqNo, type, plaintext, offset, len); + byte[] ciphertext = new byte[len + mac.length]; + System.arraycopy(plaintext, offset, ciphertext, 0, len); + System.arraycopy(mac, 0, ciphertext, len, mac.length); + return ciphertext; + } + + public byte[] decodeCiphertext(long seqNo, short type, byte[] ciphertext, int offset, int len) + throws IOException + { + int macSize = readMac.getSize(); + if (len < macSize) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + int macInputLen = len - macSize; + + byte[] receivedMac = Arrays.copyOfRange(ciphertext, offset + macInputLen, offset + len); + byte[] computedMac = readMac.calculateMac(seqNo, type, ciphertext, offset, macInputLen); + + if (!Arrays.constantTimeAreEqual(receivedMac, computedMac)) + { + throw new TlsFatalAlert(AlertDescription.bad_record_mac); + } + + return Arrays.copyOfRange(ciphertext, offset, offset + macInputLen); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsStreamCipherImpl.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsStreamCipherImpl.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsStreamCipherImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsStreamCipherImpl.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,39 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +/** + * Interface for stream cipher services. + */ +public interface TlsStreamCipherImpl +{ + /** + * Set the key to be used by the stream cipher implementation supporting this service. + * + * @param key the stream cipher key. + */ + void setKey(byte[] key) throws IOException; + + /** + * Initialise the parameters for stream cipher. + * + * @param nonce the nonce for the stream cipher. + * @throws IOException if the parameters are inappropriate. + */ + void init(byte[] nonce) throws IOException; + + /** + * Perform the cipher encryption/decryption returning the output in output. + *

      + * Note: we have to use doFinal() here as it is the only way to guarantee output from the underlying cipher. + *

      + * @param input array holding input data to the cipher. + * @param inputOffset offset into input array data starts at. + * @param inputLength length of the input data in the array. + * @param output array to hold the cipher output. + * @param outputOffset offset into output array to start saving output. + * @return the amount of data written to output. + * @throws IOException in case of failure. + */ + int doFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsStreamCipher.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsStreamCipher.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsStreamCipher.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsStreamCipher.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,163 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsHMAC; +import org.bouncycastle.util.Arrays; + +/** + * A generic TLS 1.0-1.2 / SSLv3 stream cipher. + */ +public class TlsStreamCipher + implements TlsCipher +{ + protected TlsCryptoParameters cryptoParams; + + protected TlsStreamCipherImpl encryptCipher; + protected TlsStreamCipherImpl decryptCipher; + + protected TlsSuiteMac writeMac; + protected TlsSuiteMac readMac; + + protected boolean usesNonce; + + public TlsStreamCipher(TlsCryptoParameters cryptoParams, TlsStreamCipherImpl encryptCipher, + TlsStreamCipherImpl decryptCipher, TlsHMAC clientWriteDigest, TlsHMAC serverWriteDigest, + int cipherKeySize, boolean usesNonce) throws IOException + { + boolean isServer = cryptoParams.isServer(); + + this.cryptoParams = cryptoParams; + this.usesNonce = usesNonce; + + this.encryptCipher = encryptCipher; + this.decryptCipher = decryptCipher; + + int key_block_size = (2 * cipherKeySize) + clientWriteDigest.getMacLength() + + serverWriteDigest.getMacLength(); + + byte[] key_block = TlsImplUtils.calculateKeyBlock(cryptoParams, key_block_size); + + int offset = 0; + + // Init MACs + TlsSuiteMac clientWriteMac = new TlsSuiteHMac(cryptoParams, clientWriteDigest); + clientWriteMac.setKey(Arrays.copyOfRange(key_block, offset, offset + clientWriteDigest.getMacLength())); + offset += clientWriteDigest.getMacLength(); + TlsSuiteMac serverWriteMac = new TlsSuiteHMac(cryptoParams, serverWriteDigest); + serverWriteMac.setKey(Arrays.copyOfRange(key_block, offset, offset + serverWriteDigest.getMacLength())); + offset += serverWriteDigest.getMacLength(); + + // Build keys + byte[] clientWriteKey = Arrays.copyOfRange(key_block, offset, offset + cipherKeySize); + offset += cipherKeySize; + byte[] serverWriteKey = Arrays.copyOfRange(key_block, offset, offset + cipherKeySize); + offset += cipherKeySize; + + if (offset != key_block_size) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + byte[] encryptParams, decryptParams; + if (isServer) + { + this.writeMac = serverWriteMac; + this.readMac = clientWriteMac; + encryptParams = serverWriteKey; + decryptParams = clientWriteKey; + } + else + { + this.writeMac = clientWriteMac; + this.readMac = serverWriteMac; + encryptParams = clientWriteKey; + decryptParams = serverWriteKey; + } + + this.encryptCipher.setKey(encryptParams); + this.decryptCipher.setKey(decryptParams); + if (usesNonce) + { + byte[] dummyNonce = new byte[8]; + this.encryptCipher.init(dummyNonce); + this.decryptCipher.init(dummyNonce); + } + else + { + this.encryptCipher.init(null); + this.decryptCipher.init(null); + } + } + + public int getPlaintextLimit(int ciphertextLimit) + { + return ciphertextLimit - writeMac.getSize(); + } + + public byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len) + throws IOException + { + if (usesNonce) + { + updateIV(encryptCipher, true, seqNo); + } + + byte[] outBuf = new byte[len + writeMac.getSize()]; + byte[] mac = writeMac.calculateMac(seqNo, type, plaintext, offset, len); + + System.arraycopy(plaintext, offset, outBuf, 0, len); + System.arraycopy(mac, 0, outBuf, len, mac.length); + + encryptCipher.doFinal(outBuf, 0, outBuf.length, outBuf, 0); + + return outBuf; + } + + public byte[] decodeCiphertext(long seqNo, short type, byte[] ciphertext, int offset, int len) + throws IOException + { + if (usesNonce) + { + updateIV(decryptCipher, false, seqNo); + } + + int macSize = readMac.getSize(); + if (len < macSize) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + int plaintextLength = len - macSize; + + byte[] deciphered = new byte[len]; + decryptCipher.doFinal(ciphertext, offset, len, deciphered, 0); + checkMAC(seqNo, type, deciphered, plaintextLength, len, deciphered, 0, plaintextLength); + return Arrays.copyOfRange(deciphered, 0, plaintextLength); + } + + protected void checkMAC(long seqNo, short type, byte[] recBuf, int recStart, int recEnd, byte[] calcBuf, int calcOff, int calcLen) + throws IOException + { + byte[] receivedMac = Arrays.copyOfRange(recBuf, recStart, recEnd); + byte[] computedMac = readMac.calculateMac(seqNo, type, calcBuf, calcOff, calcLen); + + if (!Arrays.constantTimeAreEqual(receivedMac, computedMac)) + { + throw new TlsFatalAlert(AlertDescription.bad_record_mac); + } + } + + protected void updateIV(org.bouncycastle.tls.crypto.impl.TlsStreamCipherImpl cipher, boolean forEncryption, long seqNo) + throws IOException + { + byte[] nonce = new byte[8]; + TlsUtils.writeUint64(seqNo, nonce, 0); + cipher.init(nonce); + } +} \ No newline at end of file diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsSuiteHMac.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsSuiteHMac.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsSuiteHMac.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsSuiteHMac.java 2016-10-05 02:27:16.000000000 +0000 @@ -0,0 +1,157 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsHMAC; +import org.bouncycastle.util.Arrays; + +/** + * A generic TLS MAC implementation, acting as an HMAC based on some underlying Digest. + */ +class TlsSuiteHMac + implements TlsSuiteMac +{ + protected TlsCryptoParameters cryptoParams; + protected byte[] secret; + protected TlsHMAC mac; + protected int digestBlockSize; + protected int digestOverhead; + protected int macLength; + + /** + * Generate a new instance of an TlsMac. + * + * @param cryptoParams the TLS client context specific crypto parameters. + * @param mac The MAC to use. + */ + public TlsSuiteHMac(TlsCryptoParameters cryptoParams, TlsHMAC mac) + { + this.cryptoParams = cryptoParams; + + this.digestBlockSize = mac.getInternalBlockSize(); + this.digestOverhead = digestBlockSize / 8; + + if (TlsImplUtils.isSSL(cryptoParams)) + { + // TODO This should check the actual algorithm, not assume based on the digest size + if (mac.getMacLength() == 20) + { + /* + * NOTE: When SHA-1 is used with the SSL 3.0 MAC, the secret + input pad is not + * digest block-aligned. + */ + this.digestOverhead = 4; + } + } + + // NOTE: The input pad for HMAC is always a full digest block + this.mac = mac; + } + + public void setKey(byte[] key) + throws IOException + { + this.secret = Arrays.clone(key); + + this.mac.setKey(secret); + + this.macLength = mac.getMacLength(); + if (cryptoParams.getSecurityParameters().isTruncatedHMac()) + { + this.macLength = Math.min(this.macLength, 10); + } + } + + /** + * @return the MAC write secret + */ + public byte[] getMACSecret() + { + return this.secret; + } + + /** + * @return The output length of this MAC. + */ + public int getSize() + { + return macLength; + } + + /** + * Calculate the MAC for some given data. + * + * @param type The message type of the message. + * @param message A byte-buffer containing the message. + * @param offset The number of bytes to skip, before the message starts. + * @param length The length of the message. + * @return A new byte-buffer containing the MAC value. + */ + public byte[] calculateMac(long seqNo, short type, byte[] message, int offset, int length) + { + ProtocolVersion serverVersion = cryptoParams.getServerVersion(); + boolean isSSL = serverVersion.isSSL(); + + byte[] macHeader = new byte[isSSL ? 11 : 13]; + TlsUtils.writeUint64(seqNo, macHeader, 0); + TlsUtils.writeUint8(type, macHeader, 8); + if (!isSSL) + { + TlsUtils.writeVersion(serverVersion, macHeader, 9); + } + TlsUtils.writeUint16(length, macHeader, macHeader.length - 2); + + mac.update(macHeader, 0, macHeader.length); + mac.update(message, offset, length); + + return truncate(mac.calculateMAC()); + } + + public byte[] calculateMacConstantTime(long seqNo, short type, byte[] message, int offset, int length, + int expectedLength, byte[] dummyData) + { + /* + * Actual MAC only calculated on 'length' bytes... + */ + byte[] result = calculateMac(seqNo, type, message, offset, length); + + /* + * ...but ensure a constant number of complete digest blocks are processed (as many as would + * be needed for 'fullLength' bytes of input). + */ + int headerLength = TlsImplUtils.isSSL(cryptoParams) ? 11 : 13; + + // How many extra full blocks do we need to calculate? + int extra = getDigestBlockCount(headerLength + expectedLength) - getDigestBlockCount(headerLength + length); + + while (--extra >= 0) + { + mac.update(dummyData, 0, digestBlockSize); + } + + // One more byte in case the implementation is "lazy" about processing blocks + mac.update(dummyData, 0, 1); + mac.reset(); + + return result; + } + + protected int getDigestBlockCount(int inputLength) + { + // NOTE: This calculation assumes a minimum of 1 pad byte + return (inputLength + digestOverhead) / digestBlockSize; + } + + protected byte[] truncate(byte[] bs) + { + if (bs.length <= macLength) + { + return bs; + } + + return Arrays.copyOf(bs, macLength); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsSuiteMac.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsSuiteMac.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsSuiteMac.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsSuiteMac.java 2016-10-04 07:34:17.000000000 +0000 @@ -0,0 +1,50 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +/** + * Base interface for a generic TLS MAC implementation for use with a cipher suite. + */ +public interface TlsSuiteMac +{ + /** + * Set the key to be used with the MAC. + * + * @param macKey the bytes representing the key. + * @throws IOException an initialization exception. + */ + void setKey(byte[] macKey) + throws IOException; + + /** + * Return the output length (in bytes) of this MAC. + * + * @return The output length of this MAC. + */ + int getSize(); + + /** + * Calculate the MAC for some given data. + * + * @param type The message type of the message. + * @param message A byte array containing the message. + * @param offset The number of bytes to skip, before the message starts. + * @param length The length of the message. + * @return A new byte array containing the MAC value. + */ + byte[] calculateMac(long seqNo, short type, byte[] message, int offset, int length); + + /** + * Constant time calculation of the MAC for some given data with a given expected length. + * + * @param seqNo The sequence number of the cipher text. + * @param type The content type of the message. + * @param message A byte array containing the message. + * @param offset The number of bytes to skip, before the message starts. + * @param length The length of the message. + * @param expectedLength The expected length of the full message, + * @param randomData Random data for padding out the MAC calculation if required. + * @return A new byte array containing the MAC value. + */ + byte[] calculateMacConstantTime(long seqNo, short type, byte[] message, int offset, int length, int expectedLength, byte[] randomData); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/SRP6Group.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/SRP6Group.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/SRP6Group.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/SRP6Group.java 2016-10-02 23:54:13.000000000 +0000 @@ -0,0 +1,33 @@ +package org.bouncycastle.tls.crypto; + +import java.math.BigInteger; + +/** + * Carrier class for SRP-6 group parameters. + */ +public class SRP6Group +{ + private BigInteger N, g; + + /** + * Base constructor. + * + * @param N the N value. + * @param g the g value. + */ + public SRP6Group(BigInteger N, BigInteger g) + { + this.N = N; + this.g = g; + } + + public BigInteger getG() + { + return g; + } + + public BigInteger getN() + { + return N; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/SRP6StandardGroups.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/SRP6StandardGroups.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/SRP6StandardGroups.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/SRP6StandardGroups.java 2016-10-02 23:54:13.000000000 +0000 @@ -0,0 +1,159 @@ +package org.bouncycastle.tls.crypto; + +import java.math.BigInteger; + +import org.bouncycastle.util.encoders.Hex; + +/** + * A selection of standard groups for SRP-6. + */ +public class SRP6StandardGroups +{ + private static BigInteger fromHex(String hex) + { + return new BigInteger(1, Hex.decode(hex)); + } + + private static SRP6Group fromNG(String hexN, String hexG) + { + return new SRP6Group(fromHex(hexN), fromHex(hexG)); + } + + /* + * RFC 5054 + */ + private static final String rfc5054_1024_N = "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" + + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" + + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" + + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" + "FD5138FE8376435B9FC61D2FC0EB06E3"; + private static final String rfc5054_1024_g = "02"; + public static final SRP6Group rfc5054_1024 = fromNG(rfc5054_1024_N, rfc5054_1024_g); + + private static final String rfc5054_1536_N = "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA961" + + "4B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F843" + + "80B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0B" + + "E3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF5" + + "6EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734A" + + "F7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E" + + "8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB"; + private static final String rfc5054_1536_g = "02"; + public static final SRP6Group rfc5054_1536 = fromNG(rfc5054_1536_N, rfc5054_1536_g); + + private static final String rfc5054_2048_N = "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC319294" + + "3DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310D" + + "CD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FB" + + "D5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF74" + + "7359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A" + + "436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D" + + "5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E73" + + "03CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6" + + "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F" + "9E4AFF73"; + private static final String rfc5054_2048_g = "02"; + public static final SRP6Group rfc5054_2048 = fromNG(rfc5054_2048_N, rfc5054_2048_g); + + private static final String rfc5054_3072_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + "E0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"; + private static final String rfc5054_3072_g = "05"; + public static final SRP6Group rfc5054_3072 = fromNG(rfc5054_3072_N, rfc5054_3072_g); + + private static final String rfc5054_4096_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + "FFFFFFFFFFFFFFFF"; + private static final String rfc5054_4096_g = "05"; + public static final SRP6Group rfc5054_4096 = fromNG(rfc5054_4096_N, rfc5054_4096_g); + + private static final String rfc5054_6144_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + "6DCC4024FFFFFFFFFFFFFFFF"; + private static final String rfc5054_6144_g = "05"; + public static final SRP6Group rfc5054_6144 = fromNG(rfc5054_6144_N, rfc5054_6144_g); + + private static final String rfc5054_8192_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + + "6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA" + + "3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C" + + "5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" + + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886" + + "2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6" + + "6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5" + + "0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268" + + "359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6" + + "FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF"; + private static final String rfc5054_8192_g = "13"; + public static final SRP6Group rfc5054_8192 = fromNG(rfc5054_8192_N, rfc5054_8192_g); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsAgreement.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsAgreement.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsAgreement.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsAgreement.java 2016-09-30 23:36:39.000000000 +0000 @@ -0,0 +1,32 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; + +/** + * Base interface for ephemeral key agreement calculator. + */ +public interface TlsAgreement +{ + /** + * Generate an ephemeral key pair, returning the encoding of the public key. + * + * @return a byte encoding of the public key. + * @throws IOException in case of error. + */ + byte[] generateEphemeral() throws IOException; + + /** + * Pass in the public key for the peer to the agreement calculator. + * + * @param peerValue a byte encoding of the peer public key. + * @throws IOException in case of error. + */ + void receivePeerValue(byte[] peerValue) throws IOException; + + /** + * Calculate the agreed secret based on the calculator's current state. + * @return the calculated secret. + * @throws IOException in case of error. + */ + TlsSecret calculateSecret() throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCertificate.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCertificate.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCertificate.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCertificate.java 2016-10-02 23:50:06.000000000 +0000 @@ -0,0 +1,36 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; + +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.ConnectionEnd; +import org.bouncycastle.tls.KeyExchangeAlgorithm; +import org.bouncycastle.tls.SignatureAlgorithm; + +/** + * Interface providing the functional representation of a single X.509 certificate. + */ +public interface TlsCertificate +{ + /** + * @param signatureAlgorithm + * {@link SignatureAlgorithm} + */ + TlsVerifier createVerifier(short signatureAlgorithm) throws IOException; + + /** + * @return {@link ClientCertificateType} + */ + short getClientCertificateType() throws IOException; + + byte[] getEncoded() throws IOException; + + /** + * @param connectionEnd + * {@link ConnectionEnd} + * @param keyExchangeAlgorithm + * {@link KeyExchangeAlgorithm} + */ + // TODO[tls-ops] This is expected to be only transitional and eventually redundant + TlsCertificate useInRole(int connectionEnd, int keyExchangeAlgorithm) throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCipher.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCipher.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCipher.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCipher.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,44 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; + +/** + * Base interface for a TLS cipher suite. + */ +public interface TlsCipher +{ + /** + * Return the maximum size for the plaintext given ciphertextlimit bytes of ciphertext. + * @param ciphertextLimit the maximum number of bytes of ciphertext. + * @return the maximum size of the plaintext for ciphertextlimit bytes of input. + */ + int getPlaintextLimit(int ciphertextLimit); + + /** + * Encrypt and MAC the passed in plain text using the current cipher suite. + * + * @param seqNo sequence number of the message represented by plaintext. + * @param type content type of the message represented by plaintext. + * @param plaintext array holding input plain text to the cipher. + * @param offset offset into input array the plain text starts at. + * @param len length of the plaintext in the array. + * @return the resulting cipher text. + * @throws IOException + */ + byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len) + throws IOException; + + /** + * Validate and decrypt the passed in cipher text using the current cipher suite. + * + * @param seqNo sequence number of the message represented by ciphertext. + * @param type content type of the message represented by ciphertext. + * @param ciphertext array holding input cipher text to the cipher. + * @param offset offset into input array the cipher text starts at. + * @param len length of the cipher text in the array. + * @return the resulting plaintext. + * @throws IOException + */ + byte[] decodeCiphertext(long seqNo, short type, byte[] ciphertext, int offset, int len) + throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoException.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoException.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoException.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoException.java 2016-12-10 06:25:56.000000000 +0000 @@ -0,0 +1,24 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; + + +/** + * Basic exception class for crypto services to pass back a cause. + */ +public class TlsCryptoException + extends IOException +{ + private final Throwable cause; + + public TlsCryptoException(String msg, Throwable cause) + { + super(msg); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java 2016-11-14 07:41:28.000000000 +0000 @@ -0,0 +1,172 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.tls.MACAlgorithm; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; + +/** + * Service and object creation interface for the primitive types and services that are associated + * with cryptography in the API. + */ +public interface TlsCrypto +{ + /** + * Return true if this TlsCrypto can support the passed in block/stream encryption algorithm. + * + * @param encryptionAlgorithm the algorithm of interest. + * @return true if encryptionAlgorithm is supported, false otherwise. + */ + boolean hasEncryptionAlgorithm(int encryptionAlgorithm); + + /** + * Return true if this TlsCrypto can support the passed in hash algorithm. + * + * @param hashAlgorithm the algorithm of interest. + * @return true if hashAlgorithm is supported, false otherwise. + */ + boolean hasHashAlgorithm(short hashAlgorithm); + + /** + * Return true if this TlsCrypto can support the passed in MAC algorithm. + * + * @param macAlgorithm the algorithm of interest. + * @return true if macAlgorithm is supported, false otherwise. + */ + boolean hasMacAlgorithm(int macAlgorithm); + + /** + * Return true if this TlsCrypto can support the passed in signature algorithm. + * + * @param sigAndHashAlgorithm the algorithm of interest. + * @return true if sigAndHashAlgorithm is supported, false otherwise. + */ + boolean hasSignatureAndHashAlgorithm(SignatureAndHashAlgorithm sigAndHashAlgorithm); + + /** + * Return true if this TlsCrypto can support RSA encryption/decryption. + * + * @return true if this instance can support RSA encryption/decryption, false otherwise. + */ + boolean hasRSAEncryption(); + + /** + * Create a TlsSecret object based provided data. + * + * @param data the data to base the TlsSecret on. + * @return a TlsSecret based on random data. + */ + TlsSecret createSecret(byte[] data); + + /** + * Create a TlsSecret object containing a randomly-generated RSA PreMasterSecret + * + * @param clientVersion the client version to place in the first 2 bytes + * @return a TlsSecret containing the PreMasterSecret. + */ + TlsSecret generateRSAPreMasterSecret(ProtocolVersion clientVersion); + + /** + * Return the primary (safest) SecureRandom for this crypto. + * + * @return a SecureRandom suitable for key generation. + */ + SecureRandom getSecureRandom(); + + /** + * Create a TlsCertificate from a ASN.1 binary encoding of an X.509 certificate. + * + * @param encoding DER/BER encoding of the certificate of interest. + * @return a TlsCertificate. + * + * @throws IOException if there is an issue on decoding or constructing the certificate. + */ + TlsCertificate createCertificate(byte[] encoding) throws IOException; + + /** + * Create an domain object supporting the domain parameters described in dhConfig. + * + * @param dhConfig the config describing the DH parameters to use. + * @return a TlsECDomain supporting the parameters in ecConfig. + */ + TlsDHDomain createDHDomain(TlsDHConfig dhConfig); + + /** + * Create an domain object supporting the domain parameters described in ecConfig. + * + * @param ecConfig the config describing the EC parameters to use. + * @return a TlsECDomain supporting the parameters in ecConfig. + */ + TlsECDomain createECDomain(TlsECConfig ecConfig); + + /** + * Adopt the passed in secret, creating a new copy of it.. + * + * @param secret the secret to make a copy of. + * @return a TlsSecret based the original secret. + */ + TlsSecret adoptSecret(TlsSecret secret); + + /** + * Create a suitable hash for the signature algorithm identifier passed in. + * + * @param sidAlgorithm the signature algorithm the hash needs to match. + * @return a TlsHash. + */ + TlsHash createHash(SignatureAndHashAlgorithm sidAlgorithm); + + /** + * Create a suitable hash for the hash algorithm identifier passed in. + * + * @param algorithm the hash algorithm the hash needs to implement. + * @return a TlsHash. + */ + TlsHash createHash(short algorithm); + + /** + * Create a suitable HMAC for the MAC algorithm identifier passed in. + *

      + * See enumeration class {@link MACAlgorithm} for appropriate argument values. + *

      + * @param macAlgorithm the MAC algorithm the HMAC needs to match. + * @return a TlsHMAC. + */ + TlsHMAC createHMAC(int macAlgorithm) + throws IOException; + + /** + * Create a nonce byte[] string. + * + * @param size the length, in bytes, of the nonce to generate. + * @return the nonce value. + */ + byte[] createNonce(int size); + + /** + * Create an SRP-6 client. + * + * @param srpConfig client config. + * @return an initialised SRP6 client object, + */ + TlsSRP6Client createSRP6Client(TlsSRPConfig srpConfig); + + /** + * Create an SRP-6 server. + * + * @param srpConfig server config. + * @param srpVerifier the SRP6 verifier value. + * @return an initialised SRP6 server object. + */ + TlsSRP6Server createSRP6Server(TlsSRPConfig srpConfig, BigInteger srpVerifier); + + /** + * Create an SRP-6 verifier generator. + * + * @param srpConfig generator config. + * @return an initialized SRP6 verifier generator, + */ + TlsSRP6VerifierGenerator createSRP6VerifierGenerator(TlsSRPConfig srpConfig); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoParameters.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoParameters.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoParameters.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoParameters.java 2016-10-05 02:57:13.000000000 +0000 @@ -0,0 +1,43 @@ +package org.bouncycastle.tls.crypto; + +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SecurityParameters; +import org.bouncycastle.tls.TlsContext; + +/** + * Carrier class for context related parameters needed for creating secrets and cipher suites, + */ +public class TlsCryptoParameters +{ + private final TlsContext context; + + /** + * Base constructor. + * + * @param context the context for this parameters object. + */ + public TlsCryptoParameters(TlsContext context) + { + this.context = context; + } + + public SecurityParameters getSecurityParameters() + { + return context.getSecurityParameters(); + } + + public ProtocolVersion getClientVersion() + { + return context.getClientVersion(); + } + + public ProtocolVersion getServerVersion() + { + return context.getServerVersion(); + } + + public boolean isServer() + { + return context.isServer(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoProvider.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoProvider.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoProvider.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCryptoProvider.java 2016-11-04 00:16:57.000000000 +0000 @@ -0,0 +1,27 @@ +package org.bouncycastle.tls.crypto; + + +import java.security.SecureRandom; + +/** + * Interface that provider's of TlsCrypto implementations need to conform to. + */ +public interface TlsCryptoProvider +{ + /** + * Create a TlsCrypto using the passed in sources of entropy for key material and nonce generation. + * + * @param random SecureRandom for generating key material and seeds for nonce generation. + * @return a TlsCrypto. + */ + TlsCrypto create(SecureRandom random); + + /** + * Create a TlsCrypto using the passed in sources of entropy for keys and nonces. + * + * @param keyRandom SecureRandom for generating key material. + * @param nonceRandom SecureRandom for generating nonces. + * @return a TlsCrypto. + */ + TlsCrypto create(SecureRandom keyRandom, SecureRandom nonceRandom); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsDHConfig.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsDHConfig.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsDHConfig.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsDHConfig.java 2016-10-03 01:39:03.000000000 +0000 @@ -0,0 +1,31 @@ +package org.bouncycastle.tls.crypto; + +import java.math.BigInteger; + +/** + * Basic config for Diffie-Hellman. + */ +public class TlsDHConfig +{ + protected BigInteger[] explicitPG; + + /** + * Return the (p, g) values used in Diffie-Hellman. + * + * @return (p, g) as a BigInteger array (p=[0], g =[1]). + */ + public BigInteger[] getExplicitPG() + { + return explicitPG.clone(); + } + + /** + * Set the (p, g) values used in Diffie-Hellman. + * + * @param explicitPG (p, g) as a BigInteger array (p=[0], g =[1]). + */ + public void setExplicitPG(BigInteger[] explicitPG) + { + this.explicitPG = explicitPG.clone(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsDHDomain.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsDHDomain.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsDHDomain.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsDHDomain.java 2016-10-05 02:02:23.000000000 +0000 @@ -0,0 +1,14 @@ +package org.bouncycastle.tls.crypto; + +/** + * Domain interface to service factory for creating Diffie-Hellman operators. + */ +public interface TlsDHDomain +{ + /** + * Return an agreement operator suitable for ephemeral Diffie-Hellman. + * + * @return a key agreement operator. + */ + TlsAgreement createDH(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsECConfig.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsECConfig.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsECConfig.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsECConfig.java 2016-10-03 23:38:18.000000000 +0000 @@ -0,0 +1,50 @@ +package org.bouncycastle.tls.crypto; + +/** + * Carrier class for Elliptic Curve parameter configuration. + */ +public class TlsECConfig +{ + protected int namedCurve; + protected boolean pointCompression; + + /** + * Return the TLS identifier of the named curve associated with this config. + * + * @return the TLS ID for the curve this config is for. + */ + public int getNamedCurve() + { + return namedCurve; + } + + /** + * Set the curve to use. + * + * @param namedCurve the TLS ID for the curve to use. + */ + public void setNamedCurve(int namedCurve) + { + this.namedCurve = namedCurve; + } + + /** + * Return whether or not point compression is enabled for this config. + * + * @return true if point compression is enabled, false otherwise. + */ + public boolean getPointCompression() + { + return pointCompression; + } + + /** + * Set whether point compression should be enabled for this config. + * + * @param pointCompression true if point compression should be enabled. + */ + public void setPointCompression(boolean pointCompression) + { + this.pointCompression = pointCompression; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsECDomain.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsECDomain.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsECDomain.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsECDomain.java 2016-10-05 02:02:00.000000000 +0000 @@ -0,0 +1,14 @@ +package org.bouncycastle.tls.crypto; + +/** + * Domain interface to service factory for creating Elliptic-Curve (EC) based operators. + */ +public interface TlsECDomain +{ + /** + * Return an agreement operator suitable for ephemeral EC Diffie-Hellman. + * + * @return a key agreement operator. + */ + TlsAgreement createECDH(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsHash.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsHash.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsHash.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsHash.java 2016-10-09 23:59:29.000000000 +0000 @@ -0,0 +1,35 @@ +package org.bouncycastle.tls.crypto; + +/** + * Interface for message digest, or hash, services. + */ +public interface TlsHash +{ + /** + * Update the hash with the passed in input. + * + * @param input input array containing the data. + * @param inOff offset into the input array the input starts at. + * @param length the length of the input data. + */ + void update(byte[] input, int inOff, int length); + + /** + * Return calculated hash for any input passed in. + * + * @return the hash value. + */ + byte[] calculateHash(); + + /** + * Return a clone of this hash object representing its current state. + * + * @return a clone of the current hash. + */ + Object clone(); + + /** + * Reset the hash underlying this service. + */ + void reset(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsHMAC.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsHMAC.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsHMAC.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsHMAC.java 2016-10-04 00:05:48.000000000 +0000 @@ -0,0 +1,15 @@ +package org.bouncycastle.tls.crypto; + +/** + * Interface for MAC services based on HMAC. + */ +public interface TlsHMAC + extends TlsMAC +{ + /** + * Return the internal block size for the message digest underlying this HMAC service. + * + * @return the internal block size for the digest (in bytes). + */ + int getInternalBlockSize(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsMAC.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsMAC.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsMAC.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsMAC.java 2016-09-15 02:38:29.000000000 +0000 @@ -0,0 +1,42 @@ +package org.bouncycastle.tls.crypto; + +/** + * Interface for MAC services. + */ +public interface TlsMAC +{ + /** + * Set the key to be used by the MAC implementation supporting this service. + * + * @param key the MAC key. + */ + void setKey(byte[] key); + + /** + * Update the MAC with the passed in input. + * + * @param input input array containing the data. + * @param inOff offset into the input array the input starts at. + * @param length the length of the input data. + */ + void update(byte[] input, int inOff, int length); + + /** + * Return calculated MAC for any input passed in. + * + * @return the MAC value. + */ + byte[] calculateMAC(); + + /** + * Return the length of the MAC generated by this service. + * + * @return the MAC length. + */ + int getMacLength(); + + /** + * Reset the MAC underlying this service. + */ + void reset(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsNullNullCipher.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsNullNullCipher.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsNullNullCipher.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsNullNullCipher.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,29 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; + +/** + * The cipher for TLS_NULL_WITH_NULL_NULL. + */ +public class TlsNullNullCipher + implements TlsCipher +{ + public int getPlaintextLimit(int ciphertextLimit) + { + return ciphertextLimit; + } + + public byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len) + throws IOException + { + return Arrays.copyOfRange(plaintext, offset, offset + len); + } + + public byte[] decodeCiphertext(long seqNo, short type, byte[] ciphertext, int offset, int len) + throws IOException + { + return Arrays.copyOfRange(ciphertext, offset, offset + len); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSecret.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSecret.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSecret.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSecret.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,75 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; + +import org.bouncycastle.tls.EncryptionAlgorithm; +import org.bouncycastle.tls.MACAlgorithm; + +/** + * Interface supporting the generation of key material and other SSL/TLS secret values from PRFs. + */ +public interface TlsSecret +{ + /** + * Derive a new SSL key block using the passed in seed. + * + * @param seed the joint random value. + * @param length the length (in bytes) required. + * @return the newly derived secret. + */ + TlsSecret deriveSSLKeyBlock(byte[] seed, int length); + + /** + * Derive a new SSL master secret using the passed in seed. + * + * @param seed the session hash or joint random value. + * @return the newly derived secret. + */ + TlsSecret deriveSSLMasterSecret(byte[] seed); + + /** + * Return a new secret based on applying a PRF to this one. + * + * @param prfAlgorithm PRF algorithm to use. + * @param labelSeed the appropriate concatenation of the label and seed details + * @param length the size (in bytes) of the secret to generate. + * @return the new secret. + */ + TlsSecret deriveUsingPRF(int prfAlgorithm, byte[] labelSeed, int length); + + /** + * Create a cipher suite that matches the passed in encryption algorithm and mac algorithm. + *

      + * See enumeration classes {@link EncryptionAlgorithm}, {@link MACAlgorithm} for appropriate argument values. + *

      + * @param contextParams context specific parameters. + * @param encryptionAlgorithm the encryption algorithm to be employed by the cipher suite. + * @param macAlgorithm the MAC algorithm to be employed by the cipher suite. + * @return a TlsCipherSuite supporting the encryption and mac algorithm. + * @throws IOException + */ + TlsCipher createCipher(TlsCryptoParameters contextParams, int encryptionAlgorithm, int macAlgorithm) throws IOException; + + /** + * Destroy the internal state of the secret. After this call, any attempt to use the + * {@link TlsSecret} will result in an {@link IllegalStateException} being thrown. + */ + void destroy(); + + /** + * Return the an encrypted copy of the data this secret is based on. + * + * @param certificate the certificate containing the public key to use for protecting the internal data. + * @return an encrypted copy of secret's internal data. + */ + byte[] encrypt(TlsCertificate certificate) throws IOException; + + /** + * Return the internal data from this secret. The {@link TlsSecret} does not keep a copy of the + * data. After this call, any attempt to use the {@link TlsSecret} will result in an + * {@link IllegalStateException} being thrown. + * + * @return the secret's internal data. + */ + byte[] extract(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSigner.java 2016-10-09 23:52:38.000000000 +0000 @@ -0,0 +1,22 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; + +import org.bouncycastle.tls.SignatureAndHashAlgorithm; + +/** + * Base interface for a TLS signer that works on raw message digests. + */ +public interface TlsSigner +{ + /** + * Generate an encoded signature based on the passed in hash, + * + * @param algorithm the signature algorithm to use. + * @param hash the hash calculated for the signature. + * @return an encoded signature. + * @throws IOException in case of an exception processing the hash. + */ + byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, byte[] hash) + throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6Client.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6Client.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6Client.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6Client.java 2016-10-01 21:56:18.000000000 +0000 @@ -0,0 +1,28 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; +import java.math.BigInteger; + +/** + * Basic interface for an SRP-6 client implementation. + */ +public interface TlsSRP6Client +{ + /** + * Generates the secret S given the server's credentials + * @param serverB The server's credentials + * @return Client's verification message for the server + * @throws IOException If server's credentials are invalid + */ + BigInteger calculateSecret(BigInteger serverB) + throws IOException; + + /** + * Generates client's credentials given the client's salt, identity and password + * @param salt The salt used in the client's verifier. + * @param identity The user's identity (eg. username) + * @param password The user's password + * @return Client's public value to send to server + */ + BigInteger generateClientCredentials(byte[] salt, byte[] identity, byte[] password); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6Server.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6Server.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6Server.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6Server.java 2016-10-01 21:56:18.000000000 +0000 @@ -0,0 +1,24 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; +import java.math.BigInteger; + +/** + * Basic interface for an SRP-6 server implementation. + */ +public interface TlsSRP6Server +{ + /** + * Generates the server's credentials that are to be sent to the client. + * @return The server's public value to the client + */ + BigInteger generateServerCredentials(); + + /** + * Processes the client's credentials. If valid the shared secret is generated and returned. + * @param clientA The client's credentials + * @return A shared secret BigInteger + * @throws IOException If client's credentials are invalid + */ + BigInteger calculateSecret(BigInteger clientA) throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6VerifierGenerator.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6VerifierGenerator.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6VerifierGenerator.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRP6VerifierGenerator.java 2016-10-03 23:40:27.000000000 +0000 @@ -0,0 +1,19 @@ +package org.bouncycastle.tls.crypto; + +import java.math.BigInteger; + +/** + * Base interface for a generator for SRP-6 verifiers. + */ +public interface TlsSRP6VerifierGenerator +{ + /** + * Creates a new SRP-6 verifier value. + * + * @param salt The salt to use, generally should be large and random + * @param identity The user's identifying information (eg. username) + * @param password The user's password + * @return A new verifier for use in future SRP authentication + */ + BigInteger generateVerifier(byte[] salt, byte[] identity, byte[] password); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRPConfig.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRPConfig.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRPConfig.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsSRPConfig.java 2016-10-03 01:35:21.000000000 +0000 @@ -0,0 +1,31 @@ +package org.bouncycastle.tls.crypto; + +import java.math.BigInteger; + +/** + * Basic config for SRP. + */ +public class TlsSRPConfig +{ + protected BigInteger[] explicitNG; + + /** + * Return the (N, g) values used in SRP-6. + * + * @return (N, g) as a BigInteger array (N=[0], g =[1]). + */ + public BigInteger[] getExplicitNG() + { + return explicitNG.clone(); + } + + /** + * Set the (N, g) values used for SRP-6. + * + * @param explicitNG (N, g) as a BigInteger array (N=[0], g =[1]). + */ + public void setExplicitNG(BigInteger[] explicitNG) + { + this.explicitNG = explicitNG.clone(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/crypto/TlsVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/crypto/TlsVerifier.java 2016-10-03 01:49:36.000000000 +0000 @@ -0,0 +1,21 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; + +import org.bouncycastle.tls.DigitallySigned; + +/** + * Base interface for a TLS verfier that works with signatures and raw message digests. + */ +public interface TlsVerifier +{ + /** + * Return true if the passed in signature and hash represent a real signature. + * + * @param signature the signature object containg the signature to be verified. + * @param hash the hash calculated for the signature. + * @return true if signature verifies, false otherwise. + * @throws IOException in case of an exception verifying signature. + */ + boolean verifySignature(DigitallySigned signature, byte[] hash) throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DatagramTransport.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DatagramTransport.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DatagramTransport.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DatagramTransport.java 2016-11-22 03:46:01.000000000 +0000 @@ -0,0 +1,24 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +/** + * Base interface for an object sending and receiving DTLS data. + */ +public interface DatagramTransport +{ + int getReceiveLimit() + throws IOException; + + int getSendLimit() + throws IOException; + + int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException; + + void send(byte[] buf, int off, int len) + throws IOException; + + void close() + throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsClient.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsClient.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsClient.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsClient.java 2016-11-18 12:47:10.000000000 +0000 @@ -0,0 +1,117 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.util.Arrays; + +public abstract class DefaultTlsClient + extends AbstractTlsClient +{ + // TODO[tls] Perhaps not ideal to keep this in a writable array + protected static final int[] BASE_CIPHER_SUITES = new int[] + { + CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, + }; + + protected TlsDHConfigVerifier dhConfigVerifier; + protected int[] supportedCipherSuites; + + // TODO[tls-ops] Need to restore a default constructor here + + public DefaultTlsClient(TlsCrypto crypto) + { + this(crypto, new DefaultTlsKeyExchangeFactory(), new DefaultTlsDHConfigVerifier()); + } + + public DefaultTlsClient(TlsCrypto crypto, TlsKeyExchangeFactory keyExchangeFactory, TlsDHConfigVerifier dhConfigVerifier) + { + super(crypto, keyExchangeFactory); + this.dhConfigVerifier = dhConfigVerifier; + this.supportedCipherSuites = TlsUtils.getSupportedCipherSuites(crypto, BASE_CIPHER_SUITES); + } + + public int[] getCipherSuites() + { + return Arrays.clone(supportedCipherSuites); + } + + public TlsKeyExchange getKeyExchange() + throws IOException + { + int keyExchangeAlgorithm = TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite); + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DH_anon: + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DH_RSA: + return createDHKeyExchange(keyExchangeAlgorithm); + + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_RSA: + return createDHEKeyExchange(keyExchangeAlgorithm); + + case KeyExchangeAlgorithm.ECDH_anon: + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDH_RSA: + return createECDHKeyExchange(keyExchangeAlgorithm); + + case KeyExchangeAlgorithm.ECDHE_ECDSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + return createECDHEKeyExchange(keyExchangeAlgorithm); + + case KeyExchangeAlgorithm.RSA: + return createRSAKeyExchange(); + + default: + /* + * Note: internal error here; the TlsProtocol implementation verifies that the + * server-selected cipher suite was in the list of client-offered cipher suites, so if + * we now can't produce an implementation, we shouldn't have offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + protected TlsKeyExchange createDHKeyExchange(int keyExchange) throws IOException + { + return keyExchangeFactory.createDHKeyExchangeClient(keyExchange, supportedSignatureAlgorithms, dhConfigVerifier); + } + + protected TlsKeyExchange createDHEKeyExchange(int keyExchange) throws IOException + { + return keyExchangeFactory.createDHEKeyExchangeClient(keyExchange, supportedSignatureAlgorithms, dhConfigVerifier); + } + + protected TlsKeyExchange createECDHKeyExchange(int keyExchange) throws IOException + { + return keyExchangeFactory.createECDHKeyExchangeClient(keyExchange, supportedSignatureAlgorithms, + createECConfigVerifier(), clientECPointFormats, serverECPointFormats); + } + + protected TlsKeyExchange createECDHEKeyExchange(int keyExchange) throws IOException + { + return keyExchangeFactory.createECDHEKeyExchangeClient(keyExchange, supportedSignatureAlgorithms, + createECConfigVerifier(), clientECPointFormats, serverECPointFormats); + } + + protected TlsKeyExchange createRSAKeyExchange() throws IOException + { + return keyExchangeFactory.createRSAKeyExchange(supportedSignatureAlgorithms); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsCredentialedSigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsCredentialedSigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsCredentialedSigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsCredentialedSigner.java 2016-10-09 23:42:26.000000000 +0000 @@ -0,0 +1,69 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsSigner; +import org.bouncycastle.tls.crypto.impl.TlsImplUtils; + +/** + * Container class for generating signatures that carries the signature type, parameters, public key certificate and public key's associated signer object. + */ +public class DefaultTlsCredentialedSigner + implements TlsCredentialedSigner +{ + protected TlsCryptoParameters cryptoParams; + protected Certificate certificate; + protected SignatureAndHashAlgorithm signatureAndHashAlgorithm; + + protected TlsSigner signer; + + public DefaultTlsCredentialedSigner(TlsCryptoParameters cryptoParams, TlsSigner signer, Certificate certificate, + SignatureAndHashAlgorithm signatureAndHashAlgorithm) + { + if (certificate == null) + { + throw new IllegalArgumentException("'certificate' cannot be null"); + } + if (certificate.isEmpty()) + { + throw new IllegalArgumentException("'certificate' cannot be empty"); + } + if (signer == null) + { + throw new IllegalArgumentException("'signer' cannot be null"); + } + + this.signer = signer; + + this.cryptoParams = cryptoParams; + this.certificate = certificate; + this.signatureAndHashAlgorithm = signatureAndHashAlgorithm; + } + + public Certificate getCertificate() + { + return certificate; + } + + public byte[] generateRawSignature(byte[] hash) + throws IOException + { + SignatureAndHashAlgorithm algorithm = null; + if (TlsImplUtils.isTLSv12(cryptoParams)) + { + algorithm = getSignatureAndHashAlgorithm(); + if (algorithm == null) + { + throw new IllegalStateException("'signatureAndHashAlgorithm' cannot be null for (D)TLS 1.2+"); + } + } + + return signer.generateRawSignature(algorithm, hash); + } + + public SignatureAndHashAlgorithm getSignatureAndHashAlgorithm() + { + return signatureAndHashAlgorithm; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsDHConfigVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsDHConfigVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsDHConfigVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsDHConfigVerifier.java 2016-10-25 05:52:36.000000000 +0000 @@ -0,0 +1,101 @@ +package org.bouncycastle.tls; + +import java.math.BigInteger; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.DHGroup; +import org.bouncycastle.tls.crypto.DHStandardGroups; +import org.bouncycastle.tls.crypto.TlsDHConfig; + +public class DefaultTlsDHConfigVerifier + implements TlsDHConfigVerifier +{ + public static final int DEFAULT_MINIMUM_PRIME_BITS = 1024; + + protected static final Vector DEFAULT_GROUPS = new Vector(); + + private static void addDefaultGroup(DHGroup dhParameters) + { + DEFAULT_GROUPS.addElement(TlsDHUtils.selectDHConfig(dhParameters)); + } + + static + { + addDefaultGroup(DHStandardGroups.rfc3526_1536); + addDefaultGroup(DHStandardGroups.rfc3526_2048); + addDefaultGroup(DHStandardGroups.rfc3526_3072); + addDefaultGroup(DHStandardGroups.rfc3526_4096); + addDefaultGroup(DHStandardGroups.rfc3526_6144); + addDefaultGroup(DHStandardGroups.rfc3526_8192); + + addDefaultGroup(DHStandardGroups.rfc5996_768); + addDefaultGroup(DHStandardGroups.rfc5996_1024); + } + + // Vector is (TlsDHConfig) + protected Vector groups; + protected int minimumPrimeBits; + + /** + * Accept only various standard DH groups with 'P' at least {@link #DEFAULT_MINIMUM_PRIME_BITS} bits. + */ + public DefaultTlsDHConfigVerifier() + { + this(DEFAULT_MINIMUM_PRIME_BITS); + } + + /** + * Accept only various standard DH groups with 'P' at least the specified number of bits. + */ + public DefaultTlsDHConfigVerifier(int minimumPrimeBits) + { + this(DEFAULT_GROUPS, minimumPrimeBits); + } + + /** + * Specify a custom set of acceptable group parameters, and a minimum bitlength for 'P' + * + * @param groups a {@link Vector} of acceptable {@link TlsDHConfig} + */ + public DefaultTlsDHConfigVerifier(Vector groups, int minimumPrimeBits) + { + this.groups = groups; + this.minimumPrimeBits = minimumPrimeBits; + } + + public boolean accept(TlsDHConfig dhConfig) + { + if (dhConfig.getExplicitPG()[0].bitLength() < getMinimumPrimeBits()) + { + return false; + } + for (int i = 0; i < groups.size(); ++i) + { + if (areGroupsEqual(dhConfig, (TlsDHConfig)groups.elementAt(i))) + { + return true; + } + } + return false; + } + + public int getMinimumPrimeBits() + { + return minimumPrimeBits; + } + + protected boolean areGroupsEqual(TlsDHConfig a, TlsDHConfig b) + { + return a == b || (areParametersEqual(a.getExplicitPG(), b.getExplicitPG())); + } + + protected boolean areParametersEqual(BigInteger[] pgA, BigInteger[] pgB) + { + return pgA == pgB || (areParametersEqual(pgA[0], pgB[0]) && areParametersEqual(pgA[1], pgB[1])); + } + + protected boolean areParametersEqual(BigInteger a, BigInteger b) + { + return a == b || a.equals(b); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsECConfigVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsECConfigVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsECConfigVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsECConfigVerifier.java 2016-07-21 03:43:53.000000000 +0000 @@ -0,0 +1,41 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.util.Arrays; + +public class DefaultTlsECConfigVerifier + implements TlsECConfigVerifier +{ + protected int minimumCurveBits; + protected int[] namedCurves; + + public DefaultTlsECConfigVerifier(int minimumCurveBits, int[] namedCurves) + { + this.minimumCurveBits = minimumCurveBits; + this.namedCurves = Arrays.clone(namedCurves); + } + + public boolean accept(TlsECConfig ecConfig) + { + // NOTE: Any value of ecConfig.pointCompression is acceptable + + int namedCurve = ecConfig.getNamedCurve(); + + if (NamedCurve.getCurveBits(namedCurve) < minimumCurveBits) + { + return false; + } + + if (namedCurves != null && !Arrays.contains(namedCurves, namedCurve)) + { + /* + * RFC 4492 4. [...] servers MUST NOT negotiate the use of an ECC cipher suite unless + * they can complete the handshake while respecting the choice of curves and compression + * techniques specified by the client. + */ + return false; + } + + return true; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsKeyExchangeFactory.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsKeyExchangeFactory.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsKeyExchangeFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsKeyExchangeFactory.java 2016-08-28 04:49:25.000000000 +0000 @@ -0,0 +1,96 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsECConfig; + +public class DefaultTlsKeyExchangeFactory + extends AbstractTlsKeyExchangeFactory +{ + public TlsKeyExchange createDHKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsDHConfigVerifier dhConfigVerifier) throws IOException + { + return new TlsDHKeyExchange(keyExchange, supportedSignatureAlgorithms, dhConfigVerifier); + } + + public TlsKeyExchange createDHKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsDHConfig dhConfig) throws IOException + { + return new TlsDHKeyExchange(keyExchange, supportedSignatureAlgorithms, dhConfig); + } + + public TlsKeyExchange createDHEKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsDHConfigVerifier dhConfigVerifier) throws IOException + { + return new TlsDHEKeyExchange(keyExchange, supportedSignatureAlgorithms, dhConfigVerifier); + } + + public TlsKeyExchange createDHEKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsDHConfig dhConfig) throws IOException + { + return new TlsDHEKeyExchange(keyExchange, supportedSignatureAlgorithms, dhConfig); + } + + public TlsKeyExchange createECDHKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfigVerifier ecConfigVerifier, short[] clientECPointFormats, short[] serverECPointFormats) + throws IOException + { + return new TlsECDHKeyExchange(keyExchange, supportedSignatureAlgorithms, ecConfigVerifier, clientECPointFormats, + serverECPointFormats); + } + + public TlsKeyExchange createECDHKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfig ecConfig, short[] serverECPointFormats) throws IOException + { + return new TlsECDHKeyExchange(keyExchange, supportedSignatureAlgorithms, ecConfig, serverECPointFormats); + } + + public TlsKeyExchange createECDHEKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfigVerifier ecConfigVerifier, short[] clientECPointFormats, short[] serverECPointFormats) + throws IOException + { + return new TlsECDHEKeyExchange(keyExchange, supportedSignatureAlgorithms, ecConfigVerifier, + clientECPointFormats, serverECPointFormats); + } + + public TlsKeyExchange createECDHEKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfig ecConfig, short[] serverECPointFormats) throws IOException + { + return new TlsECDHEKeyExchange(keyExchange, supportedSignatureAlgorithms, ecConfig, serverECPointFormats); + } + + public TlsKeyExchange createPSKKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsPSKIdentity pskIdentity, TlsDHConfigVerifier dhConfigVerifier, TlsECConfigVerifier ecConfigVerifier, + short[] clientECPointFormats, short[] serverECPointFormats) throws IOException + { + return new TlsPSKKeyExchange(keyExchange, supportedSignatureAlgorithms, pskIdentity, dhConfigVerifier, + ecConfigVerifier, clientECPointFormats, serverECPointFormats); + } + + public TlsKeyExchange createPSKKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsPSKIdentityManager pskIdentityManager, TlsDHConfig dhConfig, TlsECConfig ecConfig, + short[] serverECPointFormats) throws IOException + { + return new TlsPSKKeyExchange(keyExchange, supportedSignatureAlgorithms, null, pskIdentityManager, dhConfig, + ecConfig, serverECPointFormats); + } + + public TlsKeyExchange createRSAKeyExchange(Vector supportedSignatureAlgorithms) throws IOException + { + return new TlsRSAKeyExchange(supportedSignatureAlgorithms); + } + + public TlsKeyExchange createSRPKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsSRPConfigVerifier srpConfigVerifier, byte[] identity, byte[] password) throws IOException + { + return new TlsSRPKeyExchange(keyExchange, supportedSignatureAlgorithms, srpConfigVerifier, identity, password); + } + + public TlsKeyExchange createSRPKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + byte[] identity, TlsSRPLoginParameters loginParameters) throws IOException + { + return new TlsSRPKeyExchange(keyExchange, supportedSignatureAlgorithms, identity, loginParameters); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsServer.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsServer.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsServer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsServer.java 2016-11-18 12:47:10.000000000 +0000 @@ -0,0 +1,175 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.util.Arrays; + +public abstract class DefaultTlsServer + extends AbstractTlsServer +{ + // TODO[tls] Perhaps not ideal to keep this in a writable array + protected static final int[] BASE_CIPHER_SUITES = new int[] + { + CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256, + CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, + }; + + // TODO[tls-ops] Need to restore a default constructor here + + protected int[] supportedCipherSuites; + + public DefaultTlsServer(TlsCrypto crypto) + { + super(crypto); + this.supportedCipherSuites = TlsUtils.getSupportedCipherSuites(crypto, BASE_CIPHER_SUITES); + } + + public DefaultTlsServer(TlsCrypto crypto, TlsKeyExchangeFactory keyExchangeFactory) + { + super(crypto, keyExchangeFactory); + this.supportedCipherSuites = TlsUtils.getSupportedCipherSuites(crypto, BASE_CIPHER_SUITES); + } + + protected TlsCredentialedSigner getDSASignerCredentials() + throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected TlsCredentialedSigner getECDSASignerCredentials() + throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected TlsCredentialedDecryptor getRSAEncryptionCredentials() + throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected TlsCredentialedSigner getRSASignerCredentials() + throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected int[] getCipherSuites() + { + return Arrays.clone(supportedCipherSuites); + } + + public TlsCredentials getCredentials() + throws IOException + { + int keyExchangeAlgorithm = TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite); + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DHE_DSS: + return getDSASignerCredentials(); + + case KeyExchangeAlgorithm.DH_anon: + case KeyExchangeAlgorithm.ECDH_anon: + return null; + + case KeyExchangeAlgorithm.ECDHE_ECDSA: + return getECDSASignerCredentials(); + + case KeyExchangeAlgorithm.DHE_RSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + return getRSASignerCredentials(); + + case KeyExchangeAlgorithm.RSA: + return getRSAEncryptionCredentials(); + + default: + /* Note: internal error here; selected a key exchange we don't implement! */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public TlsKeyExchange getKeyExchange() + throws IOException + { + int keyExchangeAlgorithm = TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite); + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DH_anon: + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DH_RSA: + return createDHKeyExchange(keyExchangeAlgorithm); + + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_RSA: + return createDHEKeyExchange(keyExchangeAlgorithm); + + case KeyExchangeAlgorithm.ECDH_anon: + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDH_RSA: + return createECDHKeyExchange(keyExchangeAlgorithm); + + case KeyExchangeAlgorithm.ECDHE_ECDSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + return createECDHEKeyExchange(keyExchangeAlgorithm); + + case KeyExchangeAlgorithm.RSA: + return createRSAKeyExchange(); + + default: + /* + * Note: internal error here; the TlsProtocol implementation verifies that the + * server-selected cipher suite was in the list of client-offered cipher suites, so if + * we now can't produce an implementation, we shouldn't have offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + protected TlsKeyExchange createDHKeyExchange(int keyExchange) throws IOException + { + return keyExchangeFactory.createDHKeyExchangeServer(keyExchange, supportedSignatureAlgorithms, selectDHConfig()); + } + + protected TlsKeyExchange createDHEKeyExchange(int keyExchange) throws IOException + { + return keyExchangeFactory.createDHEKeyExchangeServer(keyExchange, supportedSignatureAlgorithms, selectDHConfig()); + } + + protected TlsKeyExchange createECDHKeyExchange(int keyExchange) throws IOException + { + return keyExchangeFactory.createECDHKeyExchangeServer(keyExchange, supportedSignatureAlgorithms, selectECConfig(), + serverECPointFormats); + } + + protected TlsKeyExchange createECDHEKeyExchange(int keyExchange) throws IOException + { + return keyExchangeFactory.createECDHEKeyExchangeServer(keyExchange, supportedSignatureAlgorithms, selectECConfig(), + serverECPointFormats); + } + + protected TlsKeyExchange createRSAKeyExchange() throws IOException + { + return keyExchangeFactory.createRSAKeyExchange(supportedSignatureAlgorithms); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsSRPConfigVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsSRPConfigVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DefaultTlsSRPConfigVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DefaultTlsSRPConfigVerifier.java 2016-10-01 22:06:43.000000000 +0000 @@ -0,0 +1,69 @@ +package org.bouncycastle.tls; + +import java.math.BigInteger; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.SRP6Group; +import org.bouncycastle.tls.crypto.SRP6StandardGroups; +import org.bouncycastle.tls.crypto.TlsSRPConfig; + +public class DefaultTlsSRPConfigVerifier + implements TlsSRPConfigVerifier +{ + protected static final Vector DEFAULT_GROUPS = new Vector(); + + static + { + DEFAULT_GROUPS.addElement(SRP6StandardGroups.rfc5054_1024); + DEFAULT_GROUPS.addElement(SRP6StandardGroups.rfc5054_1536); + DEFAULT_GROUPS.addElement(SRP6StandardGroups.rfc5054_2048); + DEFAULT_GROUPS.addElement(SRP6StandardGroups.rfc5054_3072); + DEFAULT_GROUPS.addElement(SRP6StandardGroups.rfc5054_4096); + DEFAULT_GROUPS.addElement(SRP6StandardGroups.rfc5054_6144); + DEFAULT_GROUPS.addElement(SRP6StandardGroups.rfc5054_8192); + } + + // Vector is (SRP6Group) + protected Vector groups; + + /** + * Accept only the group parameters specified in RFC 5054 Appendix A. + */ + public DefaultTlsSRPConfigVerifier() + { + this(DEFAULT_GROUPS); + } + + /** + * Specify a custom set of acceptable group parameters. + * + * @param groups a {@link Vector} of acceptable {@link SRP6Group} + */ + public DefaultTlsSRPConfigVerifier(Vector groups) + { + this.groups = groups; + } + + public boolean accept(TlsSRPConfig srpConfig) + { + for (int i = 0; i < groups.size(); ++i) + { + if (areGroupsEqual(srpConfig, (SRP6Group)groups.elementAt(i))) + { + return true; + } + } + return false; + } + + protected boolean areGroupsEqual(TlsSRPConfig a, SRP6Group b) + { + BigInteger[] ng = a.getExplicitNG(); + return (areParametersEqual(ng[0], b.getN()) && areParametersEqual(ng[1], b.getG())); + } + + protected boolean areParametersEqual(BigInteger a, BigInteger b) + { + return a == b || a.equals(b); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DeferredHash.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DeferredHash.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DeferredHash.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DeferredHash.java 2016-12-21 02:32:16.000000000 +0000 @@ -0,0 +1,189 @@ +package org.bouncycastle.tls; + +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bouncycastle.tls.crypto.TlsHash; +import org.bouncycastle.util.Shorts; + +/** + * Buffers input until the hash algorithm is determined. + */ +class DeferredHash + implements TlsHandshakeHash +{ + protected static final int BUFFERING_HASH_LIMIT = 4; + + protected TlsContext context; + + private DigestInputBuffer buf; + private Hashtable hashes; + private Short prfHashAlgorithm; + + DeferredHash(TlsContext context) + { + this.context = context; + this.buf = new DigestInputBuffer(); + this.hashes = new Hashtable(); + this.prfHashAlgorithm = null; + } + + private DeferredHash(TlsContext context, Short prfHashAlgorithm, TlsHash prfHash) + { + this.context = context; + this.buf = null; + this.hashes = new Hashtable(); + this.prfHashAlgorithm = prfHashAlgorithm; + hashes.put(prfHashAlgorithm, prfHash); + } + + private DeferredHash(DeferredHash defHash) + { + this.context = defHash.context; + this.buf = null;// TODO: need clone method? + this.prfHashAlgorithm = defHash.prfHashAlgorithm; + this.hashes = (Hashtable)defHash.hashes.clone(); + throw new IllegalStateException("not complete"); + } + + public TlsHandshakeHash notifyPRFDetermined() + { + int prfAlgorithm = context.getSecurityParameters().getPrfAlgorithm(); + if (prfAlgorithm == PRFAlgorithm.tls_prf_legacy) + { + CombinedHash legacyHash = new CombinedHash(context); + buf.updateDigest(legacyHash); + return legacyHash.notifyPRFDetermined(); + } + + this.prfHashAlgorithm = Shorts.valueOf(TlsUtils.getHashAlgorithmForPRFAlgorithm(prfAlgorithm)); + + checkTrackingHash(prfHashAlgorithm); + + return this; + } + + public void trackHashAlgorithm(short hashAlgorithm) + { + if (buf == null) + { + throw new IllegalStateException("Too late to track more hash algorithms"); + } + + checkTrackingHash(Shorts.valueOf(hashAlgorithm)); + } + + public void sealHashAlgorithms() + { + checkStopBuffering(); + } + + public TlsHandshakeHash stopTracking() + { + TlsHash prfHash = (TlsHash)hashes.get(prfHashAlgorithm).clone(); + if (buf != null) + { + buf.updateDigest(prfHash); + } + DeferredHash result = new DeferredHash(context, prfHashAlgorithm, prfHash); + + return result; + } + + public TlsHash forkPRFHash() + { + checkStopBuffering(); + + if (buf != null) + { + TlsHash prfHash = context.getCrypto().createHash(prfHashAlgorithm.shortValue()); + buf.updateDigest(prfHash); + return prfHash; + } + + return (TlsHash)hashes.get(prfHashAlgorithm).clone(); + } + + public byte[] getFinalHash(short hashAlgorithm) + { + TlsHash d = (TlsHash)hashes.get(Shorts.valueOf(hashAlgorithm)); + if (d == null) + { + throw new IllegalStateException("HashAlgorithm." + HashAlgorithm.getText(hashAlgorithm) + " is not being tracked"); + } + + d = (TlsHash)d.clone(); + if (buf != null) + { + buf.updateDigest(d); + } + + return d.calculateHash(); + } + + public void update(byte[] input, int inOff, int len) + { + if (buf != null) + { + buf.write(input, inOff, len); + return; + } + + Enumeration e = hashes.elements(); + while (e.hasMoreElements()) + { + TlsHash hash = (TlsHash)e.nextElement(); + hash.update(input, inOff, len); + } + } + + public byte[] calculateHash() + { + throw new IllegalStateException("Use fork() to get a definite Digest"); + } + + public Object clone() + { + throw new IllegalStateException("attempt to clone a DeferredHash"); + } + + public void reset() + { + if (buf != null) + { + buf.reset(); + return; + } + + Enumeration e = hashes.elements(); + while (e.hasMoreElements()) + { + TlsHash hash = (TlsHash)e.nextElement(); + hash.reset(); + } + } + + protected void checkStopBuffering() + { + if (buf != null && hashes.size() <= BUFFERING_HASH_LIMIT) + { + Enumeration e = hashes.elements(); + while (e.hasMoreElements()) + { + TlsHash hash = (TlsHash)e.nextElement(); + buf.updateDigest(hash); + } + + this.buf = null; + } + } + + protected void checkTrackingHash(Short hashAlgorithm) + { + if (!hashes.containsKey(hashAlgorithm)) + { + TlsHash hash = context.getCrypto().createHash(hashAlgorithm.shortValue()); + hashes.put(hashAlgorithm, hash); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DigestInputBuffer.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DigestInputBuffer.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DigestInputBuffer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DigestInputBuffer.java 2016-08-28 05:18:57.000000000 +0000 @@ -0,0 +1,13 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayOutputStream; + +import org.bouncycastle.tls.crypto.TlsHash; + +class DigestInputBuffer extends ByteArrayOutputStream +{ + void updateDigest(TlsHash d) + { + d.update(this.buf, 0, count); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DigitallySigned.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DigitallySigned.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DigitallySigned.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DigitallySigned.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,72 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class DigitallySigned +{ + protected SignatureAndHashAlgorithm algorithm; + protected byte[] signature; + + public DigitallySigned(SignatureAndHashAlgorithm algorithm, byte[] signature) + { + if (signature == null) + { + throw new IllegalArgumentException("'signature' cannot be null"); + } + + this.algorithm = algorithm; + this.signature = signature; + } + + /** + * @return a {@link SignatureAndHashAlgorithm} (or null before TLS 1.2). + */ + public SignatureAndHashAlgorithm getAlgorithm() + { + return algorithm; + } + + public byte[] getSignature() + { + return signature; + } + + /** + * Encode this {@link DigitallySigned} to an {@link OutputStream}. + * + * @param output + * the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) throws IOException + { + if (algorithm != null) + { + algorithm.encode(output); + } + TlsUtils.writeOpaque16(signature, output); + } + + /** + * Parse a {@link DigitallySigned} from an {@link InputStream}. + * + * @param context + * the {@link TlsContext} of the current connection. + * @param input + * the {@link InputStream} to parse from. + * @return a {@link DigitallySigned} object. + * @throws IOException + */ + public static DigitallySigned parse(TlsContext context, InputStream input) throws IOException + { + SignatureAndHashAlgorithm algorithm = null; + if (TlsUtils.isTLSv12(context)) + { + algorithm = SignatureAndHashAlgorithm.parse(input); + } + byte[] signature = TlsUtils.readOpaque16(input); + return new DigitallySigned(algorithm, signature); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSClientProtocol.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSClientProtocol.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSClientProtocol.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSClientProtocol.java 2016-11-21 00:44:31.000000000 +0000 @@ -0,0 +1,901 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.SecureRandom; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.util.Arrays; + +public class DTLSClientProtocol + extends DTLSProtocol +{ + public DTLSClientProtocol(SecureRandom secureRandom) + { + super(secureRandom); + } + + public DTLSTransport connect(TlsClient client, DatagramTransport transport) + throws IOException + { + if (client == null) + { + throw new IllegalArgumentException("'client' cannot be null"); + } + if (transport == null) + { + throw new IllegalArgumentException("'transport' cannot be null"); + } + + SecurityParameters securityParameters = new SecurityParameters(); + securityParameters.entity = ConnectionEnd.client; + + ClientHandshakeState state = new ClientHandshakeState(); + state.client = client; + state.clientContext = new TlsClientContextImpl(client.getCrypto(), securityParameters); + + securityParameters.clientRandom = TlsProtocol.createRandomBlock(client.shouldUseGMTUnixTime(), state.clientContext); + + client.init(state.clientContext); + + DTLSRecordLayer recordLayer = new DTLSRecordLayer(transport, state.clientContext, client, ContentType.handshake); + + TlsSession sessionToResume = state.client.getSessionToResume(); + if (sessionToResume != null && sessionToResume.isResumable()) + { + SessionParameters sessionParameters = sessionToResume.exportSessionParameters(); + if (sessionParameters != null) + { + state.tlsSession = sessionToResume; + state.sessionParameters = sessionParameters; + } + } + + try + { + return clientHandshake(state, recordLayer); + } + catch (TlsFatalAlert fatalAlert) + { + abortClientHandshake(state, recordLayer, fatalAlert.getAlertDescription()); + throw fatalAlert; + } + catch (IOException e) + { + abortClientHandshake(state, recordLayer, AlertDescription.internal_error); + throw e; + } + catch (RuntimeException e) + { + abortClientHandshake(state, recordLayer, AlertDescription.internal_error); + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + finally + { + securityParameters.clear(); + } + } + + protected void abortClientHandshake(ClientHandshakeState state, DTLSRecordLayer recordLayer, short alertDescription) + { + recordLayer.fail(alertDescription); + invalidateSession(state); + } + + protected DTLSTransport clientHandshake(ClientHandshakeState state, DTLSRecordLayer recordLayer) + throws IOException + { + SecurityParameters securityParameters = state.clientContext.getSecurityParameters(); + DTLSReliableHandshake handshake = new DTLSReliableHandshake(state.clientContext, recordLayer); + + byte[] clientHelloBody = generateClientHello(state, state.client); + + recordLayer.setWriteVersion(ProtocolVersion.DTLSv10); + + handshake.sendMessage(HandshakeType.client_hello, clientHelloBody); + + DTLSReliableHandshake.Message serverMessage = handshake.receiveMessage(); + + while (serverMessage.getType() == HandshakeType.hello_verify_request) + { + ProtocolVersion recordLayerVersion = recordLayer.getReadVersion(); + ProtocolVersion client_version = state.clientContext.getClientVersion(); + + /* + * RFC 6347 4.2.1 DTLS 1.2 server implementations SHOULD use DTLS version 1.0 regardless of + * the version of TLS that is expected to be negotiated. DTLS 1.2 and 1.0 clients MUST use + * the version solely to indicate packet formatting (which is the same in both DTLS 1.2 and + * 1.0) and not as part of version negotiation. + */ + if (!recordLayerVersion.isEqualOrEarlierVersionOf(client_version)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + recordLayer.setReadVersion(null); + + byte[] cookie = processHelloVerifyRequest(state, serverMessage.getBody()); + byte[] patched = patchClientHelloWithCookie(clientHelloBody, cookie); + + handshake.resetHandshakeMessagesDigest(); + handshake.sendMessage(HandshakeType.client_hello, patched); + + serverMessage = handshake.receiveMessage(); + } + + if (serverMessage.getType() == HandshakeType.server_hello) + { + ProtocolVersion recordLayerVersion = recordLayer.getReadVersion(); + reportServerVersion(state, recordLayerVersion); + recordLayer.setWriteVersion(recordLayerVersion); + + processServerHello(state, serverMessage.getBody()); + } + else + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + handshake.notifyHelloComplete(); + + applyMaxFragmentLengthExtension(recordLayer, securityParameters.getMaxFragmentLength()); + + if (state.resumedSession) + { + securityParameters.masterSecret = state.clientContext.getCrypto().adoptSecret(state.sessionParameters.getMasterSecret()); + recordLayer.initPendingEpoch(state.client.getCipher()); + + // NOTE: Calculated exclusive of the actual Finished message from the server + byte[] expectedServerVerifyData = TlsUtils.calculateVerifyData(state.clientContext, ExporterLabel.server_finished, + TlsProtocol.getCurrentPRFHash(state.clientContext, handshake.getHandshakeHash(), null)); + processFinished(handshake.receiveMessageBody(HandshakeType.finished), expectedServerVerifyData); + + // NOTE: Calculated exclusive of the Finished message itself + byte[] clientVerifyData = TlsUtils.calculateVerifyData(state.clientContext, ExporterLabel.client_finished, + TlsProtocol.getCurrentPRFHash(state.clientContext, handshake.getHandshakeHash(), null)); + handshake.sendMessage(HandshakeType.finished, clientVerifyData); + + handshake.finish(); + + state.clientContext.setSession(state.tlsSession); + + state.client.notifyHandshakeComplete(); + + return new DTLSTransport(recordLayer); + } + + invalidateSession(state); + + state.tlsSession = TlsUtils.importSession(state.selectedSessionID, null); + state.sessionParameters = null; + + serverMessage = handshake.receiveMessage(); + + if (serverMessage.getType() == HandshakeType.supplemental_data) + { + processServerSupplementalData(state, serverMessage.getBody()); + serverMessage = handshake.receiveMessage(); + } + else + { + state.client.processServerSupplementalData(null); + } + + state.keyExchange = state.client.getKeyExchange(); + state.keyExchange.init(state.clientContext); + + Certificate serverCertificate = null; + + if (serverMessage.getType() == HandshakeType.certificate) + { + serverCertificate = processServerCertificate(state, serverMessage.getBody()); + serverMessage = handshake.receiveMessage(); + } + else + { + // Okay, Certificate is optional + state.keyExchange.skipServerCredentials(); + } + + // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus + if (serverCertificate == null || serverCertificate.isEmpty()) + { + state.allowCertificateStatus = false; + } + + if (serverMessage.getType() == HandshakeType.certificate_status) + { + processCertificateStatus(state, serverMessage.getBody()); + serverMessage = handshake.receiveMessage(); + } + else + { + // Okay, CertificateStatus is optional + } + + if (serverMessage.getType() == HandshakeType.server_key_exchange) + { + processServerKeyExchange(state, serverMessage.getBody()); + serverMessage = handshake.receiveMessage(); + } + else + { + // Okay, ServerKeyExchange is optional + state.keyExchange.skipServerKeyExchange(); + } + + if (serverMessage.getType() == HandshakeType.certificate_request) + { + processCertificateRequest(state, serverMessage.getBody()); + + /* + * TODO Give the client a chance to immediately select the CertificateVerify hash + * algorithm here to avoid tracking the other hash algorithms unnecessarily? + */ + TlsUtils.trackHashAlgorithms(handshake.getHandshakeHash(), + state.certificateRequest.getSupportedSignatureAlgorithms()); + + serverMessage = handshake.receiveMessage(); + } + else + { + // Okay, CertificateRequest is optional + } + + if (serverMessage.getType() == HandshakeType.server_hello_done) + { + if (serverMessage.getBody().length != 0) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + } + else + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + handshake.getHandshakeHash().sealHashAlgorithms(); + + Vector clientSupplementalData = state.client.getClientSupplementalData(); + if (clientSupplementalData != null) + { + byte[] supplementalDataBody = generateSupplementalData(clientSupplementalData); + handshake.sendMessage(HandshakeType.supplemental_data, supplementalDataBody); + } + + Certificate clientCertificate = null; + + if (state.certificateRequest != null) + { + state.clientCredentials = TlsProtocol.validateCredentials( + state.authentication.getClientCredentials(state.certificateRequest)); + + /* + * RFC 5246 If no suitable certificate is available, the client MUST send a certificate + * message containing no certificates. + * + * NOTE: In previous RFCs, this was SHOULD instead of MUST. + */ + if (state.clientCredentials != null) + { + clientCertificate = state.clientCredentials.getCertificate(); + } + if (clientCertificate == null) + { + clientCertificate = Certificate.EMPTY_CHAIN; + } + + byte[] certificateBody = generateCertificate(clientCertificate); + handshake.sendMessage(HandshakeType.certificate, certificateBody); + } + + if (state.clientCredentials != null) + { + state.keyExchange.processClientCredentials(state.clientCredentials); + } + else + { + state.keyExchange.skipClientCredentials(); + } + + byte[] clientKeyExchangeBody = generateClientKeyExchange(state); + handshake.sendMessage(HandshakeType.client_key_exchange, clientKeyExchangeBody); + + TlsHandshakeHash prepareFinishHash = handshake.prepareToFinish(); + securityParameters.sessionHash = TlsProtocol.getCurrentPRFHash(state.clientContext, prepareFinishHash, null); + + TlsProtocol.establishMasterSecret(state.clientContext, state.keyExchange); + recordLayer.initPendingEpoch(state.client.getCipher()); + + if (state.clientCredentials != null && state.clientCredentials instanceof TlsCredentialedSigner) + { + TlsCredentialedSigner signerCredentials = (TlsCredentialedSigner)state.clientCredentials; + + /* + * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 + */ + SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtils.getSignatureAndHashAlgorithm( + state.clientContext, signerCredentials); + + byte[] hash; + if (signatureAndHashAlgorithm == null) + { + hash = securityParameters.getSessionHash(); + } + else + { + hash = prepareFinishHash.getFinalHash(signatureAndHashAlgorithm.getHash()); + } + + byte[] signature = signerCredentials.generateRawSignature(hash); + DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature); + byte[] certificateVerifyBody = generateCertificateVerify(state, certificateVerify); + handshake.sendMessage(HandshakeType.certificate_verify, certificateVerifyBody); + } + + // NOTE: Calculated exclusive of the Finished message itself + byte[] clientVerifyData = TlsUtils.calculateVerifyData(state.clientContext, ExporterLabel.client_finished, + TlsProtocol.getCurrentPRFHash(state.clientContext, handshake.getHandshakeHash(), null)); + handshake.sendMessage(HandshakeType.finished, clientVerifyData); + + if (state.expectSessionTicket) + { + serverMessage = handshake.receiveMessage(); + if (serverMessage.getType() == HandshakeType.session_ticket) + { + processNewSessionTicket(state, serverMessage.getBody()); + } + else + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + } + + // NOTE: Calculated exclusive of the actual Finished message from the server + byte[] expectedServerVerifyData = TlsUtils.calculateVerifyData(state.clientContext, ExporterLabel.server_finished, + TlsProtocol.getCurrentPRFHash(state.clientContext, handshake.getHandshakeHash(), null)); + processFinished(handshake.receiveMessageBody(HandshakeType.finished), expectedServerVerifyData); + + handshake.finish(); + + state.sessionParameters = new SessionParameters.Builder() + .setCipherSuite(securityParameters.getCipherSuite()) + .setCompressionAlgorithm(securityParameters.getCompressionAlgorithm()) + .setLocalCertificate(clientCertificate) + .setMasterSecret(state.clientContext.getCrypto().adoptSecret(securityParameters.getMasterSecret())) + .setNegotiatedVersion(state.clientContext.getServerVersion()) + .setPeerCertificate(serverCertificate) + .setPSKIdentity(securityParameters.getPSKIdentity()) + .setSRPIdentity(securityParameters.getSRPIdentity()) + // TODO Consider filtering extensions that aren't relevant to resumed sessions + .setServerExtensions(state.serverExtensions) + .build(); + + state.tlsSession = TlsUtils.importSession(state.tlsSession.getSessionID(), state.sessionParameters); + + state.clientContext.setSession(state.tlsSession); + + state.client.notifyHandshakeComplete(); + + return new DTLSTransport(recordLayer); + } + + protected byte[] generateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + certificateVerify.encode(buf); + return buf.toByteArray(); + } + + protected byte[] generateClientHello(ClientHandshakeState state, TlsClient client) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + ProtocolVersion client_version = client.getClientVersion(); + if (!client_version.isDTLS()) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + TlsClientContextImpl context = state.clientContext; + + context.setClientVersion(client_version); + TlsUtils.writeVersion(client_version, buf); + + SecurityParameters securityParameters = context.getSecurityParameters(); + buf.write(securityParameters.getClientRandom()); + + // Session ID + byte[] session_id = TlsUtils.EMPTY_BYTES; + if (state.tlsSession != null) + { + session_id = state.tlsSession.getSessionID(); + if (session_id == null || session_id.length > 32) + { + session_id = TlsUtils.EMPTY_BYTES; + } + } + TlsUtils.writeOpaque8(session_id, buf); + + // Cookie + TlsUtils.writeOpaque8(TlsUtils.EMPTY_BYTES, buf); + + boolean fallback = client.isFallback(); + + /* + * Cipher suites + */ + state.offeredCipherSuites = client.getCipherSuites(); + + // Integer -> byte[] + state.clientExtensions = client.getClientExtensions(); + + // Cipher Suites (and SCSV) + { + /* + * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension, + * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the + * ClientHello. Including both is NOT RECOMMENDED. + */ + byte[] renegExtData = TlsUtils.getExtensionData(state.clientExtensions, TlsProtocol.EXT_RenegotiationInfo); + boolean noRenegExt = (null == renegExtData); + + boolean noRenegSCSV = !Arrays.contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + + if (noRenegExt && noRenegSCSV) + { + // TODO Consider whether to default to a client extension instead + state.offeredCipherSuites = Arrays.append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + } + + /* + * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value + * than the latest (highest-valued) version supported by the client, it SHOULD include + * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The + * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends + * to negotiate.) + */ + if (fallback && !Arrays.contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)) + { + state.offeredCipherSuites = Arrays.append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV); + } + + TlsUtils.writeUint16ArrayWithUint16Length(state.offeredCipherSuites, buf); + } + + // TODO Add support for compression + // Compression methods + // state.offeredCompressionMethods = client.getCompressionMethods(); + state.offeredCompressionMethods = new short[]{ CompressionMethod._null }; + + TlsUtils.writeUint8ArrayWithUint8Length(state.offeredCompressionMethods, buf); + + // Extensions + if (state.clientExtensions != null) + { + TlsProtocol.writeExtensions(buf, state.clientExtensions); + } + + return buf.toByteArray(); + } + + protected byte[] generateClientKeyExchange(ClientHandshakeState state) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + state.keyExchange.generateClientKeyExchange(buf); + return buf.toByteArray(); + } + + protected void invalidateSession(ClientHandshakeState state) + { + if (state.sessionParameters != null) + { + state.sessionParameters.clear(); + state.sessionParameters = null; + } + + if (state.tlsSession != null) + { + state.tlsSession.invalidate(); + state.tlsSession = null; + } + } + + protected void processCertificateRequest(ClientHandshakeState state, byte[] body) + throws IOException + { + if (state.authentication == null) + { + /* + * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server to + * request client identification. + */ + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + state.certificateRequest = CertificateRequest.parse(state.clientContext, buf); + + TlsProtocol.assertEmpty(buf); + + state.keyExchange.validateCertificateRequest(state.certificateRequest); + } + + protected void processCertificateStatus(ClientHandshakeState state, byte[] body) + throws IOException + { + if (!state.allowCertificateStatus) + { + /* + * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the + * server MUST have included an extension of type "status_request" with empty + * "extension_data" in the extended server hello.. + */ + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + state.certificateStatus = CertificateStatus.parse(buf); + + TlsProtocol.assertEmpty(buf); + + // TODO[RFC 3546] Figure out how to provide this to the client/authentication. + } + + protected byte[] processHelloVerifyRequest(ClientHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + ProtocolVersion server_version = TlsUtils.readVersion(buf); + byte[] cookie = TlsUtils.readOpaque8(buf); + + TlsProtocol.assertEmpty(buf); + + // TODO Seems this behaviour is not yet in line with OpenSSL for DTLS 1.2 +// reportServerVersion(state, server_version); + if (!server_version.isEqualOrEarlierVersionOf(state.clientContext.getClientVersion())) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + /* + * RFC 6347 This specification increases the cookie size limit to 255 bytes for greater + * future flexibility. The limit remains 32 for previous versions of DTLS. + */ + if (!ProtocolVersion.DTLSv12.isEqualOrEarlierVersionOf(server_version) && cookie.length > 32) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + return cookie; + } + + protected void processNewSessionTicket(ClientHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + NewSessionTicket newSessionTicket = NewSessionTicket.parse(buf); + + TlsProtocol.assertEmpty(buf); + + state.client.notifyNewSessionTicket(newSessionTicket); + } + + protected Certificate processServerCertificate(ClientHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + Certificate serverCertificate = Certificate.parse(state.clientContext, buf); + + TlsProtocol.assertEmpty(buf); + + state.keyExchange.processServerCertificate(serverCertificate); + state.authentication = state.client.getAuthentication(); + state.authentication.notifyServerCertificate(serverCertificate); + + return serverCertificate; + } + + protected void processServerHello(ClientHandshakeState state, byte[] body) + throws IOException + { + SecurityParameters securityParameters = state.clientContext.getSecurityParameters(); + + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + { + ProtocolVersion server_version = TlsUtils.readVersion(buf); + reportServerVersion(state, server_version); + } + + securityParameters.serverRandom = TlsUtils.readFully(32, buf); + + state.selectedSessionID = TlsUtils.readOpaque8(buf); + if (state.selectedSessionID.length > 32) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + state.client.notifySessionID(state.selectedSessionID); + state.resumedSession = state.selectedSessionID.length > 0 && state.tlsSession != null + && Arrays.areEqual(state.selectedSessionID, state.tlsSession.getSessionID()); + + int selectedCipherSuite = TlsUtils.readUint16(buf); + if (!Arrays.contains(state.offeredCipherSuites, selectedCipherSuite) + || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL + || CipherSuite.isSCSV(selectedCipherSuite) + || !TlsUtils.isValidCipherSuiteForVersion(selectedCipherSuite, state.clientContext.getServerVersion())) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + validateSelectedCipherSuite(selectedCipherSuite, AlertDescription.illegal_parameter); + state.client.notifySelectedCipherSuite(selectedCipherSuite); + + short selectedCompressionMethod = TlsUtils.readUint8(buf); + if (!Arrays.contains(state.offeredCompressionMethods, selectedCompressionMethod)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + state.client.notifySelectedCompressionMethod(selectedCompressionMethod); + + /* + * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server + * hello message when the client has requested extended functionality via the extended + * client hello message specified in Section 2.1. ... Note that the extended server hello + * message is only sent in response to an extended client hello message. This prevents the + * possibility that the extended server hello message could "break" existing TLS 1.0 + * clients. + */ + + /* + * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore + * extensions appearing in the client hello, and send a server hello containing no + * extensions. + */ + + // Integer -> byte[] + state.serverExtensions = TlsProtocol.readExtensions(buf); + + /* + * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an + * extended client hello message. However, see RFC 5746 exception below. We always include + * the SCSV, so an Extended Server Hello is always allowed. + */ + if (state.serverExtensions != null) + { + Enumeration e = state.serverExtensions.keys(); + while (e.hasMoreElements()) + { + Integer extType = (Integer)e.nextElement(); + + /* + * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a + * ClientHello containing only the SCSV is an explicit exception to the prohibition + * in RFC 5246, Section 7.4.1.4, on the server sending unsolicited extensions and is + * only allowed because the client is signaling its willingness to receive the + * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. + */ + if (extType.equals(TlsProtocol.EXT_RenegotiationInfo)) + { + continue; + } + + /* + * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the + * same extension type appeared in the corresponding ClientHello. If a client + * receives an extension type in ServerHello that it did not request in the + * associated ClientHello, it MUST abort the handshake with an unsupported_extension + * fatal alert. + */ + if (null == TlsUtils.getExtensionData(state.clientExtensions, extType)) + { + throw new TlsFatalAlert(AlertDescription.unsupported_extension); + } + + /* + * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore + * extensions appearing in the client hello, and send a server hello containing no + * extensions[.] + */ + if (state.resumedSession) + { + // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats + // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats + // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats +// throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + /* + * RFC 5746 3.4. Client Behavior: Initial Handshake + */ + { + /* + * When a ServerHello is received, the client MUST check if it includes the + * "renegotiation_info" extension: + */ + byte[] renegExtData = TlsUtils.getExtensionData(state.serverExtensions, TlsProtocol.EXT_RenegotiationInfo); + if (renegExtData != null) + { + /* + * If the extension is present, set the secure_renegotiation flag to TRUE. The + * client MUST then verify that the length of the "renegotiated_connection" + * field is zero, and if it is not, MUST abort the handshake (by sending a fatal + * handshake_failure alert). + */ + state.secure_renegotiation = true; + + if (!Arrays.constantTimeAreEqual(renegExtData, + TlsProtocol.createRenegotiationInfo(TlsUtils.EMPTY_BYTES))) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + } + } + + // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming + state.client.notifySecureRenegotiation(state.secure_renegotiation); + + Hashtable sessionClientExtensions = state.clientExtensions, sessionServerExtensions = state.serverExtensions; + if (state.resumedSession) + { + if (selectedCipherSuite != state.sessionParameters.getCipherSuite() + || selectedCompressionMethod != state.sessionParameters.getCompressionAlgorithm()) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + sessionClientExtensions = null; + sessionServerExtensions = state.sessionParameters.readServerExtensions(); + } + + securityParameters.cipherSuite = selectedCipherSuite; + securityParameters.compressionAlgorithm = selectedCompressionMethod; + + if (sessionServerExtensions != null) + { + { + /* + * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client + * and then selects a stream or Authenticated Encryption with Associated Data (AEAD) + * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the + * client. + */ + boolean serverSentEncryptThenMAC = TlsExtensionsUtils.hasEncryptThenMACExtension(sessionServerExtensions); + if (serverSentEncryptThenMAC && !TlsUtils.isBlockCipherSuite(securityParameters.getCipherSuite())) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + securityParameters.encryptThenMAC = serverSentEncryptThenMAC; + } + + securityParameters.extendedMasterSecret = TlsExtensionsUtils.hasExtendedMasterSecretExtension(sessionServerExtensions); + + securityParameters.maxFragmentLength = evaluateMaxFragmentLengthExtension(state.resumedSession, + sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter); + + securityParameters.truncatedHMac = TlsExtensionsUtils.hasTruncatedHMacExtension(sessionServerExtensions); + + /* + * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be + * sent in a session resumption handshake. + */ + state.allowCertificateStatus = !state.resumedSession + && TlsUtils.hasExpectedEmptyExtensionData(sessionServerExtensions, TlsExtensionsUtils.EXT_status_request, + AlertDescription.illegal_parameter); + + state.expectSessionTicket = !state.resumedSession + && TlsUtils.hasExpectedEmptyExtensionData(sessionServerExtensions, TlsProtocol.EXT_SessionTicket, + AlertDescription.illegal_parameter); + } + + /* + * TODO[session-hash] + * + * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes + * that do not use the extended master secret [..]. (and see 5.2, 5.3) + */ + + if (sessionClientExtensions != null) + { + state.client.processServerExtensions(sessionServerExtensions); + } + + securityParameters.prfAlgorithm = TlsProtocol.getPRFAlgorithm(state.clientContext, + securityParameters.getCipherSuite()); + + /* + * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has + * a verify_data_length equal to 12. This includes all existing cipher suites. + */ + securityParameters.verifyDataLength = 12; + } + + protected void processServerKeyExchange(ClientHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + state.keyExchange.processServerKeyExchange(buf); + + TlsProtocol.assertEmpty(buf); + } + + protected void processServerSupplementalData(ClientHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + Vector serverSupplementalData = TlsProtocol.readSupplementalDataMessage(buf); + state.client.processServerSupplementalData(serverSupplementalData); + } + + protected void reportServerVersion(ClientHandshakeState state, ProtocolVersion server_version) + throws IOException + { + TlsClientContextImpl clientContext = state.clientContext; + ProtocolVersion currentServerVersion = clientContext.getServerVersion(); + if (null == currentServerVersion) + { + clientContext.setServerVersion(server_version); + state.client.notifyServerVersion(server_version); + } + else if (!currentServerVersion.equals(server_version)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + + protected static byte[] patchClientHelloWithCookie(byte[] clientHelloBody, byte[] cookie) + throws IOException + { + int sessionIDPos = 34; + int sessionIDLength = TlsUtils.readUint8(clientHelloBody, sessionIDPos); + + int cookieLengthPos = sessionIDPos + 1 + sessionIDLength; + int cookiePos = cookieLengthPos + 1; + + byte[] patched = new byte[clientHelloBody.length + cookie.length]; + System.arraycopy(clientHelloBody, 0, patched, 0, cookieLengthPos); + TlsUtils.checkUint8(cookie.length); + TlsUtils.writeUint8(cookie.length, patched, cookieLengthPos); + System.arraycopy(cookie, 0, patched, cookiePos, cookie.length); + System.arraycopy(clientHelloBody, cookiePos, patched, cookiePos + cookie.length, clientHelloBody.length + - cookiePos); + + return patched; + } + + protected static class ClientHandshakeState + { + TlsClient client = null; + TlsClientContextImpl clientContext = null; + TlsSession tlsSession = null; + SessionParameters sessionParameters = null; + SessionParameters.Builder sessionParametersBuilder = null; + int[] offeredCipherSuites = null; + short[] offeredCompressionMethods = null; + Hashtable clientExtensions = null; + Hashtable serverExtensions = null; + byte[] selectedSessionID = null; + boolean resumedSession = false; + boolean secure_renegotiation = false; + boolean allowCertificateStatus = false; + boolean expectSessionTicket = false; + TlsKeyExchange keyExchange = null; + TlsAuthentication authentication = null; + CertificateStatus certificateStatus = null; + CertificateRequest certificateRequest = null; + TlsCredentials clientCredentials = null; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSEpoch.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSEpoch.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSEpoch.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSEpoch.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,54 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsCipher; + +class DTLSEpoch +{ + private final DTLSReplayWindow replayWindow = new DTLSReplayWindow(); + + private final int epoch; + private final TlsCipher cipher; + + private long sequenceNumber = 0; + + DTLSEpoch(int epoch, TlsCipher cipher) + { + if (epoch < 0) + { + throw new IllegalArgumentException("'epoch' must be >= 0"); + } + if (cipher == null) + { + throw new IllegalArgumentException("'cipher' cannot be null"); + } + + this.epoch = epoch; + this.cipher = cipher; + } + + long allocateSequenceNumber() + { + // TODO Check for overflow + return sequenceNumber++; + } + + TlsCipher getCipher() + { + return cipher; + } + + int getEpoch() + { + return epoch; + } + + DTLSReplayWindow getReplayWindow() + { + return replayWindow; + } + + long getSequenceNumber() + { + return sequenceNumber; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSHandshakeRetransmit.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSHandshakeRetransmit.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSHandshakeRetransmit.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSHandshakeRetransmit.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,9 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +interface DTLSHandshakeRetransmit +{ + void receivedHandshakeRecord(int epoch, byte[] buf, int off, int len) + throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSProtocol.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSProtocol.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSProtocol.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSProtocol.java 2016-07-21 03:43:53.000000000 +0000 @@ -0,0 +1,99 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.SecureRandom; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.util.Arrays; + +public abstract class DTLSProtocol +{ + protected final SecureRandom secureRandom; + + protected DTLSProtocol(SecureRandom secureRandom) + { + if (secureRandom == null) + { + throw new IllegalArgumentException("'secureRandom' cannot be null"); + } + + this.secureRandom = secureRandom; + } + + protected void processFinished(byte[] body, byte[] expected_verify_data) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + byte[] verify_data = TlsUtils.readFully(expected_verify_data.length, buf); + + TlsProtocol.assertEmpty(buf); + + if (!Arrays.constantTimeAreEqual(expected_verify_data, verify_data)) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + } + + protected static void applyMaxFragmentLengthExtension(DTLSRecordLayer recordLayer, short maxFragmentLength) + throws IOException + { + if (maxFragmentLength >= 0) + { + if (!MaxFragmentLength.isValid(maxFragmentLength)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + int plainTextLimit = 1 << (8 + maxFragmentLength); + recordLayer.setPlaintextLimit(plainTextLimit); + } + } + + protected static short evaluateMaxFragmentLengthExtension(boolean resumedSession, Hashtable clientExtensions, + Hashtable serverExtensions, short alertDescription) throws IOException + { + short maxFragmentLength = TlsExtensionsUtils.getMaxFragmentLengthExtension(serverExtensions); + if (maxFragmentLength >= 0) + { + if (!MaxFragmentLength.isValid(maxFragmentLength) + || (!resumedSession && maxFragmentLength != TlsExtensionsUtils + .getMaxFragmentLengthExtension(clientExtensions))) + { + throw new TlsFatalAlert(alertDescription); + } + } + return maxFragmentLength; + } + + protected static byte[] generateCertificate(Certificate certificate) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + certificate.encode(buf); + return buf.toByteArray(); + } + + protected static byte[] generateSupplementalData(Vector supplementalData) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + TlsProtocol.writeSupplementalData(buf, supplementalData); + return buf.toByteArray(); + } + + protected static void validateSelectedCipherSuite(int selectedCipherSuite, short alertDescription) + throws IOException + { + switch (TlsUtils.getEncryptionAlgorithm(selectedCipherSuite)) + { + case EncryptionAlgorithm.RC4_40: + case EncryptionAlgorithm.RC4_128: + case -1: + throw new TlsFatalAlert(alertDescription); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSReassembler.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSReassembler.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSReassembler.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSReassembler.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,132 @@ +package org.bouncycastle.tls; + +import java.util.Vector; + +class DTLSReassembler +{ + /* + * No 'final' modifiers so that it works in earlier JDKs + */ + private short msg_type; + private byte[] body; + + private Vector missing = new Vector(); + + DTLSReassembler(short msg_type, int length) + { + this.msg_type = msg_type; + this.body = new byte[length]; + this.missing.addElement(new Range(0, length)); + } + + short getMsgType() + { + return msg_type; + } + + byte[] getBodyIfComplete() + { + return missing.isEmpty() ? body : null; + } + + void contributeFragment(short msg_type, int length, byte[] buf, int off, int fragment_offset, + int fragment_length) + { + int fragment_end = fragment_offset + fragment_length; + + if (this.msg_type != msg_type || this.body.length != length || fragment_end > length) + { + return; + } + + if (fragment_length == 0) + { + // NOTE: Empty messages still require an empty fragment to complete it + if (fragment_offset == 0 && !missing.isEmpty()) + { + Range firstRange = (Range)missing.firstElement(); + if (firstRange.getEnd() == 0) + { + missing.removeElementAt(0); + } + } + return; + } + + for (int i = 0; i < missing.size(); ++i) + { + Range range = (Range)missing.elementAt(i); + if (range.getStart() >= fragment_end) + { + break; + } + if (range.getEnd() > fragment_offset) + { + + int copyStart = Math.max(range.getStart(), fragment_offset); + int copyEnd = Math.min(range.getEnd(), fragment_end); + int copyLength = copyEnd - copyStart; + + System.arraycopy(buf, off + copyStart - fragment_offset, body, copyStart, + copyLength); + + if (copyStart == range.getStart()) + { + if (copyEnd == range.getEnd()) + { + missing.removeElementAt(i--); + } + else + { + range.setStart(copyEnd); + } + } + else + { + if (copyEnd != range.getEnd()) + { + missing.insertElementAt(new Range(copyEnd, range.getEnd()), ++i); + } + range.setEnd(copyStart); + } + } + } + } + + void reset() + { + this.missing.removeAllElements(); + this.missing.addElement(new Range(0, body.length)); + } + + private static class Range + { + private int start, end; + + Range(int start, int end) + { + this.start = start; + this.end = end; + } + + public int getStart() + { + return start; + } + + public void setStart(int start) + { + this.start = start; + } + + public int getEnd() + { + return end; + } + + public void setEnd(int end) + { + this.end = end; + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSRecordLayer.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSRecordLayer.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSRecordLayer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSRecordLayer.java 2016-11-11 19:24:50.000000000 +0000 @@ -0,0 +1,542 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsNullNullCipher; + +class DTLSRecordLayer + implements DatagramTransport +{ + private static final int RECORD_HEADER_LENGTH = 13; + private static final int MAX_FRAGMENT_LENGTH = 1 << 14; + private static final long TCP_MSL = 1000L * 60 * 2; + private static final long RETRANSMIT_TIMEOUT = TCP_MSL * 2; + + private final DatagramTransport transport; + private final TlsContext context; + private final TlsPeer peer; + + private final ByteQueue recordQueue = new ByteQueue(); + + private volatile boolean closed = false; + private volatile boolean failed = false; + private volatile ProtocolVersion readVersion = null, writeVersion = null; + private volatile boolean inHandshake; + private volatile int plaintextLimit; + private DTLSEpoch currentEpoch, pendingEpoch; + private DTLSEpoch readEpoch, writeEpoch; + + private DTLSHandshakeRetransmit retransmit = null; + private DTLSEpoch retransmitEpoch = null; + private long retransmitExpiry = 0; + + DTLSRecordLayer(DatagramTransport transport, TlsContext context, TlsPeer peer, short contentType) + { + this.transport = transport; + this.context = context; + this.peer = peer; + + this.inHandshake = true; + + this.currentEpoch = new DTLSEpoch(0, new TlsNullNullCipher()); + this.pendingEpoch = null; + this.readEpoch = currentEpoch; + this.writeEpoch = currentEpoch; + + setPlaintextLimit(MAX_FRAGMENT_LENGTH); + } + + void setPlaintextLimit(int plaintextLimit) + { + this.plaintextLimit = plaintextLimit; + } + + ProtocolVersion getReadVersion() + { + return readVersion; + } + + void setReadVersion(ProtocolVersion readVersion) + { + this.readVersion = readVersion; + } + + void setWriteVersion(ProtocolVersion writeVersion) + { + this.writeVersion = writeVersion; + } + + void initPendingEpoch(TlsCipher pendingCipher) + { + if (pendingEpoch != null) + { + throw new IllegalStateException(); + } + + /* + * TODO "In order to ensure that any given sequence/epoch pair is unique, implementations + * MUST NOT allow the same epoch value to be reused within two times the TCP maximum segment + * lifetime." + */ + + // TODO Check for overflow + this.pendingEpoch = new DTLSEpoch(writeEpoch.getEpoch() + 1, pendingCipher); + } + + void handshakeSuccessful(DTLSHandshakeRetransmit retransmit) + { + if (readEpoch == currentEpoch || writeEpoch == currentEpoch) + { + // TODO + throw new IllegalStateException(); + } + + if (retransmit != null) + { + this.retransmit = retransmit; + this.retransmitEpoch = currentEpoch; + this.retransmitExpiry = System.currentTimeMillis() + RETRANSMIT_TIMEOUT; + } + + this.inHandshake = false; + this.currentEpoch = pendingEpoch; + this.pendingEpoch = null; + } + + void resetWriteEpoch() + { + if (retransmitEpoch != null) + { + this.writeEpoch = retransmitEpoch; + } + else + { + this.writeEpoch = currentEpoch; + } + } + + public int getReceiveLimit() + throws IOException + { + return Math.min(this.plaintextLimit, + readEpoch.getCipher().getPlaintextLimit(transport.getReceiveLimit() - RECORD_HEADER_LENGTH)); + } + + public int getSendLimit() + throws IOException + { + return Math.min(this.plaintextLimit, + writeEpoch.getCipher().getPlaintextLimit(transport.getSendLimit() - RECORD_HEADER_LENGTH)); + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + byte[] record = null; + + for (;;) + { + int receiveLimit = Math.min(len, getReceiveLimit()) + RECORD_HEADER_LENGTH; + if (record == null || record.length < receiveLimit) + { + record = new byte[receiveLimit]; + } + + try + { + if (retransmit != null && System.currentTimeMillis() > retransmitExpiry) + { + retransmit = null; + retransmitEpoch = null; + } + + int received = receiveRecord(record, 0, receiveLimit, waitMillis); + if (received < 0) + { + return received; + } + if (received < RECORD_HEADER_LENGTH) + { + continue; + } + int length = TlsUtils.readUint16(record, 11); + if (received != (length + RECORD_HEADER_LENGTH)) + { + continue; + } + + short type = TlsUtils.readUint8(record, 0); + + // TODO Support user-specified custom protocols? + switch (type) + { + case ContentType.alert: + case ContentType.application_data: + case ContentType.change_cipher_spec: + case ContentType.handshake: + case ContentType.heartbeat: + break; + default: + // TODO Exception? + continue; + } + + int epoch = TlsUtils.readUint16(record, 3); + + DTLSEpoch recordEpoch = null; + if (epoch == readEpoch.getEpoch()) + { + recordEpoch = readEpoch; + } + else if (type == ContentType.handshake && retransmitEpoch != null + && epoch == retransmitEpoch.getEpoch()) + { + recordEpoch = retransmitEpoch; + } + + if (recordEpoch == null) + { + continue; + } + + long seq = TlsUtils.readUint48(record, 5); + if (recordEpoch.getReplayWindow().shouldDiscard(seq)) + { + continue; + } + + ProtocolVersion version = TlsUtils.readVersion(record, 1); + if (!version.isDTLS()) + { + continue; + } + + if (readVersion != null && !readVersion.equals(version)) + { + continue; + } + + byte[] plaintext = recordEpoch.getCipher().decodeCiphertext( + getMacSequenceNumber(recordEpoch.getEpoch(), seq), type, record, RECORD_HEADER_LENGTH, + received - RECORD_HEADER_LENGTH); + + recordEpoch.getReplayWindow().reportAuthenticated(seq); + + if (plaintext.length > this.plaintextLimit) + { + continue; + } + + if (readVersion == null) + { + readVersion = version; + } + + switch (type) + { + case ContentType.alert: + { + if (plaintext.length == 2) + { + short alertLevel = plaintext[0]; + short alertDescription = plaintext[1]; + + peer.notifyAlertReceived(alertLevel, alertDescription); + + if (alertLevel == AlertLevel.fatal) + { + failed(); + throw new TlsFatalAlert(alertDescription); + } + + // TODO Can close_notify be a fatal alert? + if (alertDescription == AlertDescription.close_notify) + { + closeTransport(); + } + } + + continue; + } + case ContentType.application_data: + { + if (inHandshake) + { + // TODO Consider buffering application data for new epoch that arrives + // out-of-order with the Finished message + continue; + } + break; + } + case ContentType.change_cipher_spec: + { + // Implicitly receive change_cipher_spec and change to pending cipher state + + for (int i = 0; i < plaintext.length; ++i) + { + short message = TlsUtils.readUint8(plaintext, i); + if (message != ChangeCipherSpec.change_cipher_spec) + { + continue; + } + + if (pendingEpoch != null) + { + readEpoch = pendingEpoch; + } + } + + continue; + } + case ContentType.handshake: + { + if (!inHandshake) + { + if (retransmit != null) + { + retransmit.receivedHandshakeRecord(epoch, plaintext, 0, plaintext.length); + } + + // TODO Consider support for HelloRequest + continue; + } + break; + } + case ContentType.heartbeat: + { + // TODO[RFC 6520] + continue; + } + } + + /* + * NOTE: If we receive any non-handshake data in the new epoch implies the peer has + * received our final flight. + */ + if (!inHandshake && retransmit != null) + { + this.retransmit = null; + this.retransmitEpoch = null; + } + + System.arraycopy(plaintext, 0, buf, off, plaintext.length); + return plaintext.length; + } + catch (IOException e) + { + // NOTE: Assume this is a timeout for the moment + throw e; + } + } + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + short contentType = ContentType.application_data; + + if (this.inHandshake || this.writeEpoch == this.retransmitEpoch) + { + contentType = ContentType.handshake; + + short handshakeType = TlsUtils.readUint8(buf, off); + if (handshakeType == HandshakeType.finished) + { + DTLSEpoch nextEpoch = null; + if (this.inHandshake) + { + nextEpoch = pendingEpoch; + } + else if (this.writeEpoch == this.retransmitEpoch) + { + nextEpoch = currentEpoch; + } + + if (nextEpoch == null) + { + // TODO + throw new IllegalStateException(); + } + + // Implicitly send change_cipher_spec and change to pending cipher state + + // TODO Send change_cipher_spec and finished records in single datagram? + byte[] data = new byte[]{ 1 }; + sendRecord(ContentType.change_cipher_spec, data, 0, data.length); + + writeEpoch = nextEpoch; + } + } + + sendRecord(contentType, buf, off, len); + } + + public void close() + throws IOException + { + if (!closed) + { + if (inHandshake) + { + warn(AlertDescription.user_canceled, "User canceled handshake"); + } + closeTransport(); + } + } + + void fail(short alertDescription) + { + if (!closed) + { + try + { + raiseAlert(AlertLevel.fatal, alertDescription, null, null); + } + catch (Exception e) + { + // Ignore + } + + failed = true; + + closeTransport(); + } + } + + void failed() + { + if (!closed) + { + failed = true; + + closeTransport(); + } + } + + void warn(short alertDescription, String message) + throws IOException + { + raiseAlert(AlertLevel.warning, alertDescription, message, null); + } + + private void closeTransport() + { + if (!closed) + { + /* + * RFC 5246 7.2.1. Unless some other fatal alert has been transmitted, each party is + * required to send a close_notify alert before closing the write side of the + * connection. The other party MUST respond with a close_notify alert of its own and + * close down the connection immediately, discarding any pending writes. + */ + + try + { + if (!failed) + { + warn(AlertDescription.close_notify, null); + } + transport.close(); + } + catch (Exception e) + { + // Ignore + } + + closed = true; + } + } + + private void raiseAlert(short alertLevel, short alertDescription, String message, Throwable cause) + throws IOException + { + peer.notifyAlertRaised(alertLevel, alertDescription, message, cause); + + byte[] error = new byte[2]; + error[0] = (byte)alertLevel; + error[1] = (byte)alertDescription; + + sendRecord(ContentType.alert, error, 0, 2); + } + + private int receiveRecord(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + if (recordQueue.available() > 0) + { + int length = 0; + if (recordQueue.available() >= RECORD_HEADER_LENGTH) + { + byte[] lengthBytes = new byte[2]; + recordQueue.read(lengthBytes, 0, 2, 11); + length = TlsUtils.readUint16(lengthBytes, 0); + } + + int received = Math.min(recordQueue.available(), RECORD_HEADER_LENGTH + length); + recordQueue.removeData(buf, off, received, 0); + return received; + } + + int received = transport.receive(buf, off, len, waitMillis); + if (received >= RECORD_HEADER_LENGTH) + { + int fragmentLength = TlsUtils.readUint16(buf, off + 11); + int recordLength = RECORD_HEADER_LENGTH + fragmentLength; + if (received > recordLength) + { + recordQueue.addData(buf, off + recordLength, received - recordLength); + received = recordLength; + } + } + + return received; + } + + private void sendRecord(short contentType, byte[] buf, int off, int len) + throws IOException + { + // Never send anything until a valid ClientHello has been received + if (writeVersion == null) + { + return; + } + + if (len > this.plaintextLimit) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + /* + * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert, + * or ChangeCipherSpec content types. + */ + if (len < 1 && contentType != ContentType.application_data) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + int recordEpoch = writeEpoch.getEpoch(); + long recordSequenceNumber = writeEpoch.allocateSequenceNumber(); + + byte[] ciphertext = writeEpoch.getCipher().encodePlaintext( + getMacSequenceNumber(recordEpoch, recordSequenceNumber), contentType, buf, off, len); + + // TODO Check the ciphertext length? + + byte[] record = new byte[ciphertext.length + RECORD_HEADER_LENGTH]; + TlsUtils.writeUint8(contentType, record, 0); + TlsUtils.writeVersion(writeVersion, record, 1); + TlsUtils.writeUint16(recordEpoch, record, 3); + TlsUtils.writeUint48(recordSequenceNumber, record, 5); + TlsUtils.writeUint16(ciphertext.length, record, 11); + System.arraycopy(ciphertext, 0, record, RECORD_HEADER_LENGTH, ciphertext.length); + + transport.send(record, 0, record.length); + } + + private static long getMacSequenceNumber(int epoch, long sequence_number) + { + return ((epoch & 0xFFFFFFFFL) << 48) | sequence_number; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSReliableHandshake.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSReliableHandshake.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSReliableHandshake.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSReliableHandshake.java 2016-08-27 04:15:12.000000000 +0000 @@ -0,0 +1,455 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.util.Integers; + +class DTLSReliableHandshake +{ + private final static int MAX_RECEIVE_AHEAD = 10; + + /* + * No 'final' modifiers so that it works in earlier JDKs + */ + private DTLSRecordLayer recordLayer; + + private TlsHandshakeHash handshakeHash; + + private Hashtable currentInboundFlight = new Hashtable(); + private Hashtable previousInboundFlight = null; + private Vector outboundFlight = new Vector(); + private boolean sending = true; + + private int message_seq = 0, next_receive_seq = 0; + + DTLSReliableHandshake(TlsContext context, DTLSRecordLayer transport) + { + this.recordLayer = transport; + this.handshakeHash = new DeferredHash(context); + } + + void notifyHelloComplete() + { + this.handshakeHash = handshakeHash.notifyPRFDetermined(); + } + + TlsHandshakeHash getHandshakeHash() + { + return handshakeHash; + } + + TlsHandshakeHash prepareToFinish() + { + TlsHandshakeHash result = handshakeHash; + this.handshakeHash = handshakeHash.stopTracking(); + return result; + } + + void sendMessage(short msg_type, byte[] body) + throws IOException + { + TlsUtils.checkUint24(body.length); + + if (!sending) + { + checkInboundFlight(); + sending = true; + outboundFlight.removeAllElements(); + } + + Message message = new Message(message_seq++, msg_type, body); + + outboundFlight.addElement(message); + + writeMessage(message); + updateHandshakeMessagesDigest(message); + } + + byte[] receiveMessageBody(short msg_type) + throws IOException + { + Message message = receiveMessage(); + if (message.getType() != msg_type) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + return message.getBody(); + } + + Message receiveMessage() + throws IOException + { + if (sending) + { + sending = false; + prepareInboundFlight(); + } + + // Check if we already have the next message waiting + { + DTLSReassembler next = (DTLSReassembler)currentInboundFlight.get(Integers.valueOf(next_receive_seq)); + if (next != null) + { + byte[] body = next.getBodyIfComplete(); + if (body != null) + { + previousInboundFlight = null; + return updateHandshakeMessagesDigest(new Message(next_receive_seq++, next.getMsgType(), body)); + } + } + } + + byte[] buf = null; + + // TODO Check the conditions under which we should reset this + int readTimeoutMillis = 1000; + + for (;;) + { + int receiveLimit = recordLayer.getReceiveLimit(); + if (buf == null || buf.length < receiveLimit) + { + buf = new byte[receiveLimit]; + } + + // TODO Handle records containing multiple handshake messages + + try + { + for (; ; ) + { + int received = recordLayer.receive(buf, 0, receiveLimit, readTimeoutMillis); + if (received < 0) + { + break; + } + if (received < 12) + { + continue; + } + int fragment_length = TlsUtils.readUint24(buf, 9); + if (received != (fragment_length + 12)) + { + continue; + } + int seq = TlsUtils.readUint16(buf, 4); + if (seq > (next_receive_seq + MAX_RECEIVE_AHEAD)) + { + continue; + } + short msg_type = TlsUtils.readUint8(buf, 0); + int length = TlsUtils.readUint24(buf, 1); + int fragment_offset = TlsUtils.readUint24(buf, 6); + if (fragment_offset + fragment_length > length) + { + continue; + } + + if (seq < next_receive_seq) + { + /* + * NOTE: If we receive the previous flight of incoming messages in full + * again, retransmit our last flight + */ + if (previousInboundFlight != null) + { + DTLSReassembler reassembler = (DTLSReassembler)previousInboundFlight.get(Integers + .valueOf(seq)); + if (reassembler != null) + { + reassembler.contributeFragment(msg_type, length, buf, 12, fragment_offset, + fragment_length); + + if (checkAll(previousInboundFlight)) + { + resendOutboundFlight(); + + /* + * TODO[DTLS] implementations SHOULD back off handshake packet + * size during the retransmit backoff. + */ + readTimeoutMillis = Math.min(readTimeoutMillis * 2, 60000); + + resetAll(previousInboundFlight); + } + } + } + } + else + { + DTLSReassembler reassembler = (DTLSReassembler)currentInboundFlight.get(Integers.valueOf(seq)); + if (reassembler == null) + { + reassembler = new DTLSReassembler(msg_type, length); + currentInboundFlight.put(Integers.valueOf(seq), reassembler); + } + + reassembler.contributeFragment(msg_type, length, buf, 12, fragment_offset, fragment_length); + + if (seq == next_receive_seq) + { + byte[] body = reassembler.getBodyIfComplete(); + if (body != null) + { + previousInboundFlight = null; + return updateHandshakeMessagesDigest(new Message(next_receive_seq++, + reassembler.getMsgType(), body)); + } + } + } + } + } + catch (IOException e) + { + // NOTE: Assume this is a timeout for the moment + } + + resendOutboundFlight(); + + /* + * TODO[DTLS] implementations SHOULD back off handshake packet size during the + * retransmit backoff. + */ + readTimeoutMillis = Math.min(readTimeoutMillis * 2, 60000); + } + } + + void finish() + { + DTLSHandshakeRetransmit retransmit = null; + if (!sending) + { + checkInboundFlight(); + } + else if (currentInboundFlight != null) + { + /* + * RFC 6347 4.2.4. In addition, for at least twice the default MSL defined for [TCP], + * when in the FINISHED state, the node that transmits the last flight (the server in an + * ordinary handshake or the client in a resumed handshake) MUST respond to a retransmit + * of the peer's last flight with a retransmit of the last flight. + */ + retransmit = new DTLSHandshakeRetransmit() + { + public void receivedHandshakeRecord(int epoch, byte[] buf, int off, int len) + throws IOException + { + /* + * TODO Need to handle the case where the previous inbound flight contains + * messages from two epochs. + */ + if (len < 12) + { + return; + } + int fragment_length = TlsUtils.readUint24(buf, off + 9); + if (len != (fragment_length + 12)) + { + return; + } + int seq = TlsUtils.readUint16(buf, off + 4); + if (seq >= next_receive_seq) + { + return; + } + + short msg_type = TlsUtils.readUint8(buf, off); + + // TODO This is a hack that only works until we try to support renegotiation + int expectedEpoch = msg_type == HandshakeType.finished ? 1 : 0; + if (epoch != expectedEpoch) + { + return; + } + + int length = TlsUtils.readUint24(buf, off + 1); + int fragment_offset = TlsUtils.readUint24(buf, off + 6); + if (fragment_offset + fragment_length > length) + { + return; + } + + DTLSReassembler reassembler = (DTLSReassembler)currentInboundFlight.get(Integers.valueOf(seq)); + if (reassembler != null) + { + reassembler.contributeFragment(msg_type, length, buf, off + 12, fragment_offset, + fragment_length); + if (checkAll(currentInboundFlight)) + { + resendOutboundFlight(); + resetAll(currentInboundFlight); + } + } + } + }; + } + + recordLayer.handshakeSuccessful(retransmit); + } + + void resetHandshakeMessagesDigest() + { + handshakeHash.reset(); + } + + /** + * Check that there are no "extra" messages left in the current inbound flight + */ + private void checkInboundFlight() + { + Enumeration e = currentInboundFlight.keys(); + while (e.hasMoreElements()) + { + Integer key = (Integer)e.nextElement(); + if (key.intValue() >= next_receive_seq) + { + // TODO Should this be considered an error? + } + } + } + + private void prepareInboundFlight() + { + resetAll(currentInboundFlight); + previousInboundFlight = currentInboundFlight; + currentInboundFlight = new Hashtable(); + } + + private void resendOutboundFlight() + throws IOException + { + recordLayer.resetWriteEpoch(); + for (int i = 0; i < outboundFlight.size(); ++i) + { + writeMessage((Message)outboundFlight.elementAt(i)); + } + } + + private Message updateHandshakeMessagesDigest(Message message) + throws IOException + { + if (message.getType() != HandshakeType.hello_request) + { + byte[] body = message.getBody(); + byte[] buf = new byte[12]; + TlsUtils.writeUint8(message.getType(), buf, 0); + TlsUtils.writeUint24(body.length, buf, 1); + TlsUtils.writeUint16(message.getSeq(), buf, 4); + TlsUtils.writeUint24(0, buf, 6); + TlsUtils.writeUint24(body.length, buf, 9); + handshakeHash.update(buf, 0, buf.length); + handshakeHash.update(body, 0, body.length); + } + return message; + } + + private void writeMessage(Message message) + throws IOException + { + int sendLimit = recordLayer.getSendLimit(); + int fragmentLimit = sendLimit - 12; + + // TODO Support a higher minimum fragment size? + if (fragmentLimit < 1) + { + // TODO Should we be throwing an exception here? + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + int length = message.getBody().length; + + // NOTE: Must still send a fragment if body is empty + int fragment_offset = 0; + do + { + int fragment_length = Math.min(length - fragment_offset, fragmentLimit); + writeHandshakeFragment(message, fragment_offset, fragment_length); + fragment_offset += fragment_length; + } + while (fragment_offset < length); + } + + private void writeHandshakeFragment(Message message, int fragment_offset, int fragment_length) + throws IOException + { + RecordLayerBuffer fragment = new RecordLayerBuffer(12 + fragment_length); + TlsUtils.writeUint8(message.getType(), fragment); + TlsUtils.writeUint24(message.getBody().length, fragment); + TlsUtils.writeUint16(message.getSeq(), fragment); + TlsUtils.writeUint24(fragment_offset, fragment); + TlsUtils.writeUint24(fragment_length, fragment); + fragment.write(message.getBody(), fragment_offset, fragment_length); + + fragment.sendToRecordLayer(recordLayer); + } + + private static boolean checkAll(Hashtable inboundFlight) + { + Enumeration e = inboundFlight.elements(); + while (e.hasMoreElements()) + { + if (((DTLSReassembler)e.nextElement()).getBodyIfComplete() == null) + { + return false; + } + } + return true; + } + + private static void resetAll(Hashtable inboundFlight) + { + Enumeration e = inboundFlight.elements(); + while (e.hasMoreElements()) + { + ((DTLSReassembler)e.nextElement()).reset(); + } + } + + static class Message + { + private final int message_seq; + private final short msg_type; + private final byte[] body; + + private Message(int message_seq, short msg_type, byte[] body) + { + this.message_seq = message_seq; + this.msg_type = msg_type; + this.body = body; + } + + public int getSeq() + { + return message_seq; + } + + public short getType() + { + return msg_type; + } + + public byte[] getBody() + { + return body; + } + } + + static class RecordLayerBuffer extends ByteArrayOutputStream + { + RecordLayerBuffer(int size) + { + super(size); + } + + void sendToRecordLayer(DTLSRecordLayer recordLayer) throws IOException + { + recordLayer.send(buf, 0, count); + buf = null; + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSReplayWindow.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSReplayWindow.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSReplayWindow.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSReplayWindow.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,91 @@ +package org.bouncycastle.tls; + +/** + * RFC 4347 4.1.2.5 Anti-replay + *

      + * Support fast rejection of duplicate records by maintaining a sliding receive window + *

      + */ +class DTLSReplayWindow +{ + private static final long VALID_SEQ_MASK = 0x0000FFFFFFFFFFFFL; + + private static final long WINDOW_SIZE = 64L; + + private long latestConfirmedSeq = -1; + private long bitmap = 0; + + /** + * Check whether a received record with the given sequence number should be rejected as a duplicate. + * + * @param seq the 48-bit DTLSPlainText.sequence_number field of a received record. + * @return true if the record should be discarded without further processing. + */ + boolean shouldDiscard(long seq) + { + if ((seq & VALID_SEQ_MASK) != seq) + { + return true; + } + + if (seq <= latestConfirmedSeq) + { + long diff = latestConfirmedSeq - seq; + if (diff >= WINDOW_SIZE) + { + return true; + } + if ((bitmap & (1L << diff)) != 0) + { + return true; + } + } + + return false; + } + + /** + * Report that a received record with the given sequence number passed authentication checks. + * + * @param seq the 48-bit DTLSPlainText.sequence_number field of an authenticated record. + */ + void reportAuthenticated(long seq) + { + if ((seq & VALID_SEQ_MASK) != seq) + { + throw new IllegalArgumentException("'seq' out of range"); + } + + if (seq <= latestConfirmedSeq) + { + long diff = latestConfirmedSeq - seq; + if (diff < WINDOW_SIZE) + { + bitmap |= (1L << diff); + } + } + else + { + long diff = seq - latestConfirmedSeq; + if (diff >= WINDOW_SIZE) + { + bitmap = 1; + } + else + { + bitmap <<= (int)diff; // for earlier JDKs + bitmap |= 1; + } + latestConfirmedSeq = seq; + } + } + + /** + * When a new epoch begins, sequence numbers begin again at 0 + */ + void reset() + { + latestConfirmedSeq = -1; + bitmap = 0; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSServerProtocol.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSServerProtocol.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSServerProtocol.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSServerProtocol.java 2016-11-21 00:44:31.000000000 +0000 @@ -0,0 +1,758 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.SecureRandom; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsVerifier; +import org.bouncycastle.util.Arrays; + +public class DTLSServerProtocol + extends DTLSProtocol +{ + protected boolean verifyRequests = true; + + public DTLSServerProtocol(SecureRandom secureRandom) + { + super(secureRandom); + } + + public boolean getVerifyRequests() + { + return verifyRequests; + } + + public void setVerifyRequests(boolean verifyRequests) + { + this.verifyRequests = verifyRequests; + } + + public DTLSTransport accept(TlsServer server, DatagramTransport transport) + throws IOException + { + if (server == null) + { + throw new IllegalArgumentException("'server' cannot be null"); + } + if (transport == null) + { + throw new IllegalArgumentException("'transport' cannot be null"); + } + + SecurityParameters securityParameters = new SecurityParameters(); + securityParameters.entity = ConnectionEnd.server; + + ServerHandshakeState state = new ServerHandshakeState(); + state.server = server; + state.serverContext = new TlsServerContextImpl(server.getCrypto(), securityParameters); + + securityParameters.serverRandom = TlsProtocol.createRandomBlock(server.shouldUseGMTUnixTime(), state.serverContext); + + server.init(state.serverContext); + + DTLSRecordLayer recordLayer = new DTLSRecordLayer(transport, state.serverContext, server, ContentType.handshake); + + // TODO Need to handle sending of HelloVerifyRequest without entering a full connection + + try + { + return serverHandshake(state, recordLayer); + } + catch (TlsFatalAlert fatalAlert) + { + abortServerHandshake(state, recordLayer, fatalAlert.getAlertDescription()); + throw fatalAlert; + } + catch (IOException e) + { + abortServerHandshake(state, recordLayer, AlertDescription.internal_error); + throw e; + } + catch (RuntimeException e) + { + abortServerHandshake(state, recordLayer, AlertDescription.internal_error); + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + finally + { + securityParameters.clear(); + } + } + + protected void abortServerHandshake(ServerHandshakeState state, DTLSRecordLayer recordLayer, short alertDescription) + { + recordLayer.fail(alertDescription); + invalidateSession(state); + } + + protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLayer recordLayer) + throws IOException + { + SecurityParameters securityParameters = state.serverContext.getSecurityParameters(); + DTLSReliableHandshake handshake = new DTLSReliableHandshake(state.serverContext, recordLayer); + + DTLSReliableHandshake.Message clientMessage = handshake.receiveMessage(); + + // NOTE: DTLSRecordLayer requires any DTLS version, we don't otherwise constrain this +// ProtocolVersion recordLayerVersion = recordLayer.getReadVersion(); + + if (clientMessage.getType() == HandshakeType.client_hello) + { + processClientHello(state, clientMessage.getBody()); + } + else + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + // NOTE: Currently no server support for session resumption + { + invalidateSession(state); + + state.tlsSession = TlsUtils.importSession(TlsUtils.EMPTY_BYTES, null); + state.sessionParameters = null; + } + + { + byte[] serverHelloBody = generateServerHello(state); + + applyMaxFragmentLengthExtension(recordLayer, securityParameters.getMaxFragmentLength()); + + ProtocolVersion recordLayerVersion = state.serverContext.getServerVersion(); + recordLayer.setReadVersion(recordLayerVersion); + recordLayer.setWriteVersion(recordLayerVersion); + + handshake.sendMessage(HandshakeType.server_hello, serverHelloBody); + } + + handshake.notifyHelloComplete(); + + Vector serverSupplementalData = state.server.getServerSupplementalData(); + if (serverSupplementalData != null) + { + byte[] supplementalDataBody = generateSupplementalData(serverSupplementalData); + handshake.sendMessage(HandshakeType.supplemental_data, supplementalDataBody); + } + + state.keyExchange = state.server.getKeyExchange(); + state.keyExchange.init(state.serverContext); + + state.serverCredentials = TlsProtocol.validateCredentials(state.server.getCredentials()); + + Certificate serverCertificate = null; + + if (state.serverCredentials == null) + { + state.keyExchange.skipServerCredentials(); + } + else + { + state.keyExchange.processServerCredentials(state.serverCredentials); + + serverCertificate = state.serverCredentials.getCertificate(); + byte[] certificateBody = generateCertificate(serverCertificate); + handshake.sendMessage(HandshakeType.certificate, certificateBody); + } + + // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus + if (serverCertificate == null || serverCertificate.isEmpty()) + { + state.allowCertificateStatus = false; + } + + if (state.allowCertificateStatus) + { + CertificateStatus certificateStatus = state.server.getCertificateStatus(); + if (certificateStatus != null) + { + byte[] certificateStatusBody = generateCertificateStatus(state, certificateStatus); + handshake.sendMessage(HandshakeType.certificate_status, certificateStatusBody); + } + } + + byte[] serverKeyExchange = state.keyExchange.generateServerKeyExchange(); + if (serverKeyExchange != null) + { + handshake.sendMessage(HandshakeType.server_key_exchange, serverKeyExchange); + } + + if (state.serverCredentials != null) + { + state.certificateRequest = state.server.getCertificateRequest(); + if (state.certificateRequest != null) + { + if (TlsUtils.isTLSv12(state.serverContext) != (state.certificateRequest.getSupportedSignatureAlgorithms() != null)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + state.keyExchange.validateCertificateRequest(state.certificateRequest); + + byte[] certificateRequestBody = generateCertificateRequest(state, state.certificateRequest); + handshake.sendMessage(HandshakeType.certificate_request, certificateRequestBody); + + TlsUtils.trackHashAlgorithms(handshake.getHandshakeHash(), + state.certificateRequest.getSupportedSignatureAlgorithms()); + } + } + + handshake.sendMessage(HandshakeType.server_hello_done, TlsUtils.EMPTY_BYTES); + + handshake.getHandshakeHash().sealHashAlgorithms(); + + clientMessage = handshake.receiveMessage(); + + if (clientMessage.getType() == HandshakeType.supplemental_data) + { + processClientSupplementalData(state, clientMessage.getBody()); + clientMessage = handshake.receiveMessage(); + } + else + { + state.server.processClientSupplementalData(null); + } + + if (state.certificateRequest == null) + { + state.keyExchange.skipClientCredentials(); + } + else + { + if (clientMessage.getType() == HandshakeType.certificate) + { + processClientCertificate(state, clientMessage.getBody()); + clientMessage = handshake.receiveMessage(); + } + else + { + if (TlsUtils.isTLSv12(state.serverContext)) + { + /* + * RFC 5246 If no suitable certificate is available, the client MUST send a + * certificate message containing no certificates. + * + * NOTE: In previous RFCs, this was SHOULD instead of MUST. + */ + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + notifyClientCertificate(state, Certificate.EMPTY_CHAIN); + } + } + + if (clientMessage.getType() == HandshakeType.client_key_exchange) + { + processClientKeyExchange(state, clientMessage.getBody()); + } + else + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + TlsHandshakeHash prepareFinishHash = handshake.prepareToFinish(); + securityParameters.sessionHash = TlsProtocol.getCurrentPRFHash(state.serverContext, prepareFinishHash, null); + + TlsProtocol.establishMasterSecret(state.serverContext, state.keyExchange); + recordLayer.initPendingEpoch(state.server.getCipher()); + + /* + * RFC 5246 7.4.8 This message is only sent following a client certificate that has signing + * capability (i.e., all certificates except those containing fixed Diffie-Hellman + * parameters). + */ + if (expectCertificateVerifyMessage(state)) + { + byte[] certificateVerifyBody = handshake.receiveMessageBody(HandshakeType.certificate_verify); + processCertificateVerify(state, certificateVerifyBody, prepareFinishHash); + } + + // NOTE: Calculated exclusive of the actual Finished message from the client + byte[] expectedClientVerifyData = TlsUtils.calculateVerifyData(state.serverContext, ExporterLabel.client_finished, + TlsProtocol.getCurrentPRFHash(state.serverContext, handshake.getHandshakeHash(), null)); + processFinished(handshake.receiveMessageBody(HandshakeType.finished), expectedClientVerifyData); + + if (state.expectSessionTicket) + { + NewSessionTicket newSessionTicket = state.server.getNewSessionTicket(); + byte[] newSessionTicketBody = generateNewSessionTicket(state, newSessionTicket); + handshake.sendMessage(HandshakeType.session_ticket, newSessionTicketBody); + } + + // NOTE: Calculated exclusive of the Finished message itself + byte[] serverVerifyData = TlsUtils.calculateVerifyData(state.serverContext, ExporterLabel.server_finished, + TlsProtocol.getCurrentPRFHash(state.serverContext, handshake.getHandshakeHash(), null)); + handshake.sendMessage(HandshakeType.finished, serverVerifyData); + + handshake.finish(); + + state.sessionParameters = new SessionParameters.Builder() + .setCipherSuite(securityParameters.getCipherSuite()) + .setCompressionAlgorithm(securityParameters.getCompressionAlgorithm()) + .setLocalCertificate(serverCertificate) + .setMasterSecret(state.serverContext.getCrypto().adoptSecret(securityParameters.getMasterSecret())) + .setNegotiatedVersion(state.serverContext.getServerVersion()) + .setPeerCertificate(state.clientCertificate) + .setPSKIdentity(securityParameters.getPSKIdentity()) + .setSRPIdentity(securityParameters.getSRPIdentity()) + // TODO Consider filtering extensions that aren't relevant to resumed sessions + .setServerExtensions(state.serverExtensions) + .build(); + + state.tlsSession = TlsUtils.importSession(state.tlsSession.getSessionID(), state.sessionParameters); + + state.serverContext.setSession(state.tlsSession); + + state.server.notifyHandshakeComplete(); + + return new DTLSTransport(recordLayer); + } + + protected byte[] generateCertificateRequest(ServerHandshakeState state, CertificateRequest certificateRequest) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + certificateRequest.encode(buf); + return buf.toByteArray(); + } + + protected byte[] generateCertificateStatus(ServerHandshakeState state, CertificateStatus certificateStatus) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + certificateStatus.encode(buf); + return buf.toByteArray(); + } + + protected byte[] generateNewSessionTicket(ServerHandshakeState state, NewSessionTicket newSessionTicket) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + newSessionTicket.encode(buf); + return buf.toByteArray(); + } + + protected byte[] generateServerHello(ServerHandshakeState state) + throws IOException + { + SecurityParameters securityParameters = state.serverContext.getSecurityParameters(); + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + { + ProtocolVersion server_version = state.server.getServerVersion(); + if (!server_version.isEqualOrEarlierVersionOf(state.serverContext.getClientVersion())) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + // TODO Read RFCs for guidance on the expected record layer version number + // recordStream.setReadVersion(server_version); + // recordStream.setWriteVersion(server_version); + // recordStream.setRestrictReadVersion(true); + state.serverContext.setServerVersion(server_version); + + TlsUtils.writeVersion(state.serverContext.getServerVersion(), buf); + } + + buf.write(securityParameters.getServerRandom()); + + /* + * The server may return an empty session_id to indicate that the session will not be cached + * and therefore cannot be resumed. + */ + TlsUtils.writeOpaque8(state.tlsSession.getSessionID(), buf); + + int selectedCipherSuite = state.server.getSelectedCipherSuite(); + if (!Arrays.contains(state.offeredCipherSuites, selectedCipherSuite) + || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL + || CipherSuite.isSCSV(selectedCipherSuite) + || !TlsUtils.isValidCipherSuiteForVersion(selectedCipherSuite, state.serverContext.getServerVersion())) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + validateSelectedCipherSuite(selectedCipherSuite, AlertDescription.internal_error); + securityParameters.cipherSuite = selectedCipherSuite; + + short selectedCompressionMethod = state.server.getSelectedCompressionMethod(); + if (!Arrays.contains(state.offeredCompressionMethods, selectedCompressionMethod)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + securityParameters.compressionAlgorithm = selectedCompressionMethod; + + TlsUtils.writeUint16(selectedCipherSuite, buf); + TlsUtils.writeUint8(selectedCompressionMethod, buf); + + state.serverExtensions = state.server.getServerExtensions(); + + /* + * RFC 5746 3.6. Server Behavior: Initial Handshake + */ + if (state.secure_renegotiation) + { + byte[] renegExtData = TlsUtils.getExtensionData(state.serverExtensions, TlsProtocol.EXT_RenegotiationInfo); + boolean noRenegExt = (null == renegExtData); + + if (noRenegExt) + { + /* + * Note that sending a "renegotiation_info" extension in response to a ClientHello + * containing only the SCSV is an explicit exception to the prohibition in RFC 5246, + * Section 7.4.1.4, on the server sending unsolicited extensions and is only allowed + * because the client is signaling its willingness to receive the extension via the + * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. + */ + + /* + * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty + * "renegotiation_info" extension in the ServerHello message. + */ + state.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(state.serverExtensions); + state.serverExtensions.put(TlsProtocol.EXT_RenegotiationInfo, + TlsProtocol.createRenegotiationInfo(TlsUtils.EMPTY_BYTES)); + } + } + + if (securityParameters.isExtendedMasterSecret()) + { + state.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(state.serverExtensions); + TlsExtensionsUtils.addExtendedMasterSecretExtension(state.serverExtensions); + } + + /* + * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore + * extensions appearing in the client hello, and send a server hello containing no + * extensions. + */ + + if (state.serverExtensions != null) + { + securityParameters.encryptThenMAC = TlsExtensionsUtils.hasEncryptThenMACExtension(state.serverExtensions); + + securityParameters.maxFragmentLength = evaluateMaxFragmentLengthExtension(state.resumedSession, + state.clientExtensions, state.serverExtensions, AlertDescription.internal_error); + + securityParameters.truncatedHMac = TlsExtensionsUtils.hasTruncatedHMacExtension(state.serverExtensions); + + /* + * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in + * a session resumption handshake. + */ + state.allowCertificateStatus = !state.resumedSession + && TlsUtils.hasExpectedEmptyExtensionData(state.serverExtensions, + TlsExtensionsUtils.EXT_status_request, AlertDescription.internal_error); + + state.expectSessionTicket = !state.resumedSession + && TlsUtils.hasExpectedEmptyExtensionData(state.serverExtensions, TlsProtocol.EXT_SessionTicket, + AlertDescription.internal_error); + + TlsProtocol.writeExtensions(buf, state.serverExtensions); + } + + securityParameters.prfAlgorithm = TlsProtocol.getPRFAlgorithm(state.serverContext, + securityParameters.getCipherSuite()); + + /* + * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length + * has a verify_data_length equal to 12. This includes all existing cipher suites. + */ + securityParameters.verifyDataLength = 12; + + return buf.toByteArray(); + } + + protected void invalidateSession(ServerHandshakeState state) + { + if (state.sessionParameters != null) + { + state.sessionParameters.clear(); + state.sessionParameters = null; + } + + if (state.tlsSession != null) + { + state.tlsSession.invalidate(); + state.tlsSession = null; + } + } + + protected void notifyClientCertificate(ServerHandshakeState state, Certificate clientCertificate) + throws IOException + { + if (state.certificateRequest == null) + { + throw new IllegalStateException(); + } + + if (state.clientCertificate != null) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + state.clientCertificate = clientCertificate; + + if (clientCertificate.isEmpty()) + { + state.keyExchange.skipClientCredentials(); + } + else + { + + /* + * TODO RFC 5246 7.4.6. If the certificate_authorities list in the certificate request + * message was non-empty, one of the certificates in the certificate chain SHOULD be + * issued by one of the listed CAs. + */ + + state.clientCertificateType = TlsUtils.getClientCertificateType(state.serverContext, clientCertificate, + state.serverCredentials.getCertificate()); + + state.keyExchange.processClientCertificate(clientCertificate); + } + + /* + * RFC 5246 7.4.6. If the client does not send any certificates, the server MAY at its + * discretion either continue the handshake without client authentication, or respond with a + * fatal handshake_failure alert. Also, if some aspect of the certificate chain was + * unacceptable (e.g., it was not signed by a known, trusted CA), the server MAY at its + * discretion either continue the handshake (considering the client unauthenticated) or send + * a fatal alert. + */ + state.server.notifyClientCertificate(clientCertificate); + } + + protected void processClientCertificate(ServerHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + Certificate clientCertificate = Certificate.parse(state.serverContext, buf); + + TlsProtocol.assertEmpty(buf); + + notifyClientCertificate(state, clientCertificate); + } + + protected void processCertificateVerify(ServerHandshakeState state, byte[] body, TlsHandshakeHash prepareFinishHash) + throws IOException + { + if (state.certificateRequest == null) + { + throw new IllegalStateException(); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + TlsServerContextImpl context = state.serverContext; + DigitallySigned clientCertificateVerify = DigitallySigned.parse(context, buf); + + TlsProtocol.assertEmpty(buf); + + // Verify the CertificateVerify message contains a correct signature. + try + { + SignatureAndHashAlgorithm signatureAlgorithm = clientCertificateVerify.getAlgorithm(); + + byte[] hash; + if (TlsUtils.isTLSv12(context)) + { + TlsUtils.verifySupportedSignatureAlgorithm(state.certificateRequest.getSupportedSignatureAlgorithms(), signatureAlgorithm); + hash = prepareFinishHash.getFinalHash(signatureAlgorithm.getHash()); + } + else + { + hash = context.getSecurityParameters().getSessionHash(); + } + + TlsVerifier verifier = state.clientCertificate.getCertificateAt(0) + .createVerifier(TlsUtils.getSignatureAlgorithmClient(state.clientCertificateType)); + + if (!verifier.verifySignature(clientCertificateVerify, hash)) + { + throw new TlsFatalAlert(AlertDescription.decrypt_error); + } + } + catch (TlsFatalAlert e) + { + throw e; + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.decrypt_error, e); + } + } + + protected void processClientHello(ServerHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + // TODO Read RFCs for guidance on the expected record layer version number + ProtocolVersion client_version = TlsUtils.readVersion(buf); + if (!client_version.isDTLS()) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + /* + * Read the client random + */ + byte[] client_random = TlsUtils.readFully(32, buf); + + byte[] sessionID = TlsUtils.readOpaque8(buf); + if (sessionID.length > 32) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + // TODO RFC 4347 has the cookie length restricted to 32, but not in RFC 6347 + byte[] cookie = TlsUtils.readOpaque8(buf); + + int cipher_suites_length = TlsUtils.readUint16(buf); + if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + /* + * NOTE: "If the session_id field is not empty (implying a session resumption request) this + * vector must include at least the cipher_suite from that session." + */ + state.offeredCipherSuites = TlsUtils.readUint16Array(cipher_suites_length / 2, buf); + + int compression_methods_length = TlsUtils.readUint8(buf); + if (compression_methods_length < 1) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + state.offeredCompressionMethods = TlsUtils.readUint8Array(compression_methods_length, buf); + + /* + * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore + * extensions appearing in the client hello, and send a server hello containing no + * extensions. + */ + state.clientExtensions = TlsProtocol.readExtensions(buf); + + TlsServerContextImpl context = state.serverContext; + SecurityParameters securityParameters = context.getSecurityParameters(); + + /* + * TODO[session-hash] + * + * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes + * that do not use the extended master secret [..]. (and see 5.2, 5.3) + */ + securityParameters.extendedMasterSecret = TlsExtensionsUtils.hasExtendedMasterSecretExtension(state.clientExtensions); + + context.setClientVersion(client_version); + + state.server.notifyClientVersion(client_version); + state.server.notifyFallback(Arrays.contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)); + + securityParameters.clientRandom = client_random; + + state.server.notifyOfferedCipherSuites(state.offeredCipherSuites); + state.server.notifyOfferedCompressionMethods(state.offeredCompressionMethods); + + /* + * RFC 5746 3.6. Server Behavior: Initial Handshake + */ + { + /* + * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension, + * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the + * ClientHello. Including both is NOT RECOMMENDED. + */ + + /* + * When a ClientHello is received, the server MUST check if it includes the + * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag + * to TRUE. + */ + if (Arrays.contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) + { + state.secure_renegotiation = true; + } + + /* + * The server MUST check if the "renegotiation_info" extension is included in the + * ClientHello. + */ + byte[] renegExtData = TlsUtils.getExtensionData(state.clientExtensions, TlsProtocol.EXT_RenegotiationInfo); + if (renegExtData != null) + { + /* + * If the extension is present, set secure_renegotiation flag to TRUE. The + * server MUST then verify that the length of the "renegotiated_connection" + * field is zero, and if it is not, MUST abort the handshake. + */ + state.secure_renegotiation = true; + + if (!Arrays.constantTimeAreEqual(renegExtData, TlsProtocol.createRenegotiationInfo(TlsUtils.EMPTY_BYTES))) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + } + } + + state.server.notifySecureRenegotiation(state.secure_renegotiation); + + if (state.clientExtensions != null) + { + // NOTE: Validates the padding extension data, if present + TlsExtensionsUtils.getPaddingExtension(state.clientExtensions); + + state.server.processClientExtensions(state.clientExtensions); + } + } + + protected void processClientKeyExchange(ServerHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + state.keyExchange.processClientKeyExchange(buf); + + TlsProtocol.assertEmpty(buf); + } + + protected void processClientSupplementalData(ServerHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + Vector clientSupplementalData = TlsProtocol.readSupplementalDataMessage(buf); + state.server.processClientSupplementalData(clientSupplementalData); + } + + protected boolean expectCertificateVerifyMessage(ServerHandshakeState state) + { + return state.clientCertificateType >= 0 && TlsUtils.hasSigningCapability(state.clientCertificateType); + } + + protected static class ServerHandshakeState + { + TlsServer server = null; + TlsServerContextImpl serverContext = null; + TlsSession tlsSession = null; + SessionParameters sessionParameters = null; + SessionParameters.Builder sessionParametersBuilder = null; + int[] offeredCipherSuites = null; + short[] offeredCompressionMethods = null; + Hashtable clientExtensions = null; + Hashtable serverExtensions = null; + boolean resumedSession = false; + boolean secure_renegotiation = false; + boolean allowCertificateStatus = false; + boolean expectSessionTicket = false; + TlsKeyExchange keyExchange = null; + TlsCredentials serverCredentials = null; + CertificateRequest certificateRequest = null; + short clientCertificateType = -1; + Certificate clientCertificate = null; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSTransport.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSTransport.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/DTLSTransport.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/DTLSTransport.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,80 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +public class DTLSTransport + implements DatagramTransport +{ + private final DTLSRecordLayer recordLayer; + + DTLSTransport(DTLSRecordLayer recordLayer) + { + this.recordLayer = recordLayer; + } + + public int getReceiveLimit() + throws IOException + { + return recordLayer.getReceiveLimit(); + } + + public int getSendLimit() + throws IOException + { + return recordLayer.getSendLimit(); + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + try + { + return recordLayer.receive(buf, off, len, waitMillis); + } + catch (TlsFatalAlert fatalAlert) + { + recordLayer.fail(fatalAlert.getAlertDescription()); + throw fatalAlert; + } + catch (IOException e) + { + recordLayer.fail(AlertDescription.internal_error); + throw e; + } + catch (RuntimeException e) + { + recordLayer.fail(AlertDescription.internal_error); + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + try + { + recordLayer.send(buf, off, len); + } + catch (TlsFatalAlert fatalAlert) + { + recordLayer.fail(fatalAlert.getAlertDescription()); + throw fatalAlert; + } + catch (IOException e) + { + recordLayer.fail(AlertDescription.internal_error); + throw e; + } + catch (RuntimeException e) + { + recordLayer.fail(AlertDescription.internal_error); + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } + + public void close() + throws IOException + { + recordLayer.close(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ECBasisType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ECBasisType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ECBasisType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ECBasisType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,15 @@ +package org.bouncycastle.tls; + +/** + * RFC 4492 5.4. (Errata ID: 2389) + */ +public class ECBasisType +{ + public static final short ec_basis_trinomial = 1; + public static final short ec_basis_pentanomial = 2; + + public static boolean isValid(short ecBasisType) + { + return ecBasisType >= ec_basis_trinomial && ecBasisType <= ec_basis_pentanomial; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ECCurveType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ECCurveType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ECCurveType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ECCurveType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,28 @@ +package org.bouncycastle.tls; + +/** + * RFC 4492 5.4 + */ +public class ECCurveType +{ + /** + * Indicates the elliptic curve domain parameters are conveyed verbosely, and the + * underlying finite field is a prime field. + */ + public static final short explicit_prime = 1; + + /** + * Indicates the elliptic curve domain parameters are conveyed verbosely, and the + * underlying finite field is a characteristic-2 field. + */ + public static final short explicit_char2 = 2; + + /** + * Indicates that a named curve is used. This option SHOULD be used when applicable. + */ + public static final short named_curve = 3; + + /* + * Values 248 through 255 are reserved for private use. + */ +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ECPointFormat.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ECPointFormat.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ECPointFormat.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ECPointFormat.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,15 @@ +package org.bouncycastle.tls; + +/** + * RFC 4492 5.1.2 + */ +public class ECPointFormat +{ + public static final short uncompressed = 0; + public static final short ansiX962_compressed_prime = 1; + public static final short ansiX962_compressed_char2 = 2; + + /* + * reserved (248..255) + */ +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java 2016-07-21 03:43:53.000000000 +0000 @@ -0,0 +1,67 @@ +package org.bouncycastle.tls; + +/** + * RFC 2246 + *

      + * Note that the values here are implementation-specific and arbitrary. It is recommended not to + * depend on the particular values (e.g. serialization). + */ +public class EncryptionAlgorithm +{ + public static final int NULL = 0; + public static final int RC4_40 = 1; + public static final int RC4_128 = 2; + public static final int RC2_CBC_40 = 3; + public static final int IDEA_CBC = 4; + public static final int DES40_CBC = 5; + public static final int DES_CBC = 6; + public static final int _3DES_EDE_CBC = 7; + + /* + * RFC 3268 + */ + public static final int AES_128_CBC = 8; + public static final int AES_256_CBC = 9; + + /* + * RFC 5289 + */ + public static final int AES_128_GCM = 10; + public static final int AES_256_GCM = 11; + + /* + * RFC 5932 + */ + public static final int CAMELLIA_128_CBC = 12; + public static final int CAMELLIA_256_CBC = 13; + + /* + * RFC 4162 + */ + public static final int SEED_CBC = 14; + + /* + * RFC 6655 + */ + public static final int AES_128_CCM = 15; + public static final int AES_128_CCM_8 = 16; + public static final int AES_256_CCM = 17; + public static final int AES_256_CCM_8 = 18; + + /* + * RFC 6367 + */ + public static final int CAMELLIA_128_GCM = 19; + public static final int CAMELLIA_256_GCM = 20; + + /* + * RFC 7905 + */ + public static final int CHACHA20_POLY1305 = 102; + + /* + * draft-zauner-tls-aes-ocb-04 + */ + public static final int AES_128_OCB_TAGLEN96 = 103; + public static final int AES_256_OCB_TAGLEN96 = 104; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ExporterLabel.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ExporterLabel.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ExporterLabel.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ExporterLabel.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,36 @@ +package org.bouncycastle.tls; + +/** + * RFC 5705 + */ +public class ExporterLabel +{ + /* + * RFC 5246 + */ + public static final String client_finished = "client finished"; + public static final String server_finished = "server finished"; + public static final String master_secret = "master secret"; + public static final String key_expansion = "key expansion"; + + /* + * RFC 5216 + */ + public static final String client_EAP_encryption = "client EAP encryption"; + + /* + * RFC 5281 + */ + public static final String ttls_keying_material = "ttls keying material"; + public static final String ttls_challenge = "ttls challenge"; + + /* + * RFC 5764 + */ + public static final String dtls_srtp = "EXTRACTOR-dtls_srtp"; + + /* + * draft-ietf-tls-session-hash-04 + */ + public static final String extended_master_secret = "extended master secret"; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ExtensionType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ExtensionType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ExtensionType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ExtensionType.java 2016-10-10 01:18:05.000000000 +0000 @@ -0,0 +1,113 @@ +package org.bouncycastle.tls; + +public class ExtensionType +{ + /* + * RFC 2546 2.3. + */ + public static final int server_name = 0; + public static final int max_fragment_length = 1; + public static final int client_certificate_url = 2; + public static final int trusted_ca_keys = 3; + public static final int truncated_hmac = 4; + public static final int status_request = 5; + + /* + * RFC 4681 + */ + public static final int user_mapping = 6; + + /* + * RFC 5878 + */ + public static final int client_authz = 7; + public static final int server_authz = 8; + + /* + * RFC RFC6091 + */ + public static final int cert_type = 9; + + /* + * RFC 4492 5.1. (elliptic_curves) and draft-ietf-tls-negotiated-ff-dhe-10 + */ + public static final int supported_groups = 10; + + /* + * RFC 4492 5.1. + */ + public static final int ec_point_formats = 11; + + /* + * RFC 5054 2.8.1. + */ + public static final int srp = 12; + + /* + * RFC 5246 7.4.1.4. + */ + public static final int signature_algorithms = 13; + + /* + * RFC 5764 9. + */ + public static final int use_srtp = 14; + + /* + * RFC 6520 6. + */ + public static final int heartbeat = 15; + + /* + * RFC 7301 + */ + public static final int application_layer_protocol_negotiation = 16; + + /* + * RFC 6961 + */ + public static final int status_request_v2 = 17; + + /* + * RFC 6962 + */ + public static final int signed_certificate_timestamp = 18; + + /* + * RFC 7250 + */ + public static final int client_certificate_type = 19; + public static final int server_certificate_type = 20; + + /* + * RFC 7685 + */ + public static final int padding = 21; + + /* + * RFC 7366 + */ + public static final int encrypt_then_mac = 22; + + /* + * RFC 7627 + */ + public static final int extended_master_secret = 23; + + /* + * RFC 5077 7. + */ + public static final int session_ticket = 35; + + /* + * draft-ietf-tls-negotiated-ff-dhe-01 + * + * WARNING: Placeholder value; the real value is TBA + */ + public static final int negotiated_ff_dhe_groups = 101; + + /* + * RFC 5746 3.2. + */ + public static final int renegotiation_info = 0xff01; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/FiniteFieldDHEGroup.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/FiniteFieldDHEGroup.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/FiniteFieldDHEGroup.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/FiniteFieldDHEGroup.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,18 @@ +package org.bouncycastle.tls; + +/* + * draft-ietf-tls-negotiated-ff-dhe-01 + */ +public class FiniteFieldDHEGroup +{ + public static final short ffdhe2432 = 0; + public static final short ffdhe3072 = 1; + public static final short ffdhe4096 = 2; + public static final short ffdhe6144 = 3; + public static final short ffdhe8192 = 4; + + public static boolean isValid(short group) + { + return group >= ffdhe2432 && group <= ffdhe8192; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HandshakeType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HandshakeType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HandshakeType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HandshakeType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,39 @@ +package org.bouncycastle.tls; + +public class HandshakeType +{ + /* + * RFC 2246 7.4 + */ + public static final short hello_request = 0; + public static final short client_hello = 1; + public static final short server_hello = 2; + public static final short certificate = 11; + public static final short server_key_exchange = 12; + public static final short certificate_request = 13; + public static final short server_hello_done = 14; + public static final short certificate_verify = 15; + public static final short client_key_exchange = 16; + public static final short finished = 20; + + /* + * RFC 3546 2.4 + */ + public static final short certificate_url = 21; + public static final short certificate_status = 22; + + /* + * (DTLS) RFC 4347 4.3.2 + */ + public static final short hello_verify_request = 3; + + /* + * RFC 4680 + */ + public static final short supplemental_data = 23; + + /* + * RFC 5077 + */ + public static final short session_ticket = 4; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HashAlgorithm.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HashAlgorithm.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HashAlgorithm.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HashAlgorithm.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,48 @@ +package org.bouncycastle.tls; + +/** + * RFC 5246 7.4.1.4.1 + */ +public class HashAlgorithm +{ + public static final short none = 0; + public static final short md5 = 1; + public static final short sha1 = 2; + public static final short sha224 = 3; + public static final short sha256 = 4; + public static final short sha384 = 5; + public static final short sha512 = 6; + + public static String getName(short hashAlgorithm) + { + switch (hashAlgorithm) + { + case none: + return "none"; + case md5: + return "md5"; + case sha1: + return "sha1"; + case sha224: + return "sha224"; + case sha256: + return "sha256"; + case sha384: + return "sha384"; + case sha512: + return "sha512"; + default: + return "UNKNOWN"; + } + } + + public static String getText(short hashAlgorithm) + { + return getName(hashAlgorithm) + "(" + hashAlgorithm + ")"; + } + + public static boolean isPrivate(short hashAlgorithm) + { + return 224 <= hashAlgorithm && hashAlgorithm <= 255; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HeartbeatExtension.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HeartbeatExtension.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HeartbeatExtension.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HeartbeatExtension.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,56 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class HeartbeatExtension +{ + protected short mode; + + public HeartbeatExtension(short mode) + { + if (!HeartbeatMode.isValid(mode)) + { + throw new IllegalArgumentException("'mode' is not a valid HeartbeatMode value"); + } + + this.mode = mode; + } + + public short getMode() + { + return mode; + } + + /** + * Encode this {@link HeartbeatExtension} to an {@link OutputStream}. + * + * @param output + * the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) throws IOException + { + TlsUtils.writeUint8(mode, output); + } + + /** + * Parse a {@link HeartbeatExtension} from an {@link InputStream}. + * + * @param input + * the {@link InputStream} to parse from. + * @return a {@link HeartbeatExtension} object. + * @throws IOException + */ + public static HeartbeatExtension parse(InputStream input) throws IOException + { + short mode = TlsUtils.readUint8(input); + if (!HeartbeatMode.isValid(mode)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + return new HeartbeatExtension(mode); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HeartbeatMessage.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HeartbeatMessage.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HeartbeatMessage.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HeartbeatMessage.java 2016-08-30 04:21:25.000000000 +0000 @@ -0,0 +1,110 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.io.Streams; + +public class HeartbeatMessage +{ + protected short type; + protected byte[] payload; + protected int paddingLength; + + public HeartbeatMessage(short type, byte[] payload, int paddingLength) + { + if (!HeartbeatMessageType.isValid(type)) + { + throw new IllegalArgumentException("'type' is not a valid HeartbeatMessageType value"); + } + if (payload == null || payload.length >= (1 << 16)) + { + throw new IllegalArgumentException("'payload' must have length < 2^16"); + } + if (paddingLength < 16) + { + throw new IllegalArgumentException("'paddingLength' must be at least 16"); + } + + this.type = type; + this.payload = payload; + this.paddingLength = paddingLength; + } + + /** + * Encode this {@link HeartbeatMessage} to an {@link OutputStream}. + * + * @param output + * the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(TlsContext context, OutputStream output) throws IOException + { + TlsUtils.writeUint8(type, output); + + TlsUtils.checkUint16(payload.length); + TlsUtils.writeUint16(payload.length, output); + output.write(payload); + + byte[] padding = context.getCrypto().createNonce(paddingLength); + output.write(padding); + } + + /** + * Parse a {@link HeartbeatMessage} from an {@link InputStream}. + * + * @param input + * the {@link InputStream} to parse from. + * @return a {@link HeartbeatMessage} object. + * @throws IOException + */ + public static HeartbeatMessage parse(InputStream input) throws IOException + { + short type = TlsUtils.readUint8(input); + if (!HeartbeatMessageType.isValid(type)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + int payload_length = TlsUtils.readUint16(input); + + PayloadBuffer buf = new PayloadBuffer(); + Streams.pipeAll(input, buf); + + byte[] payload = buf.toTruncatedByteArray(payload_length); + if (payload == null) + { + /* + * RFC 6520 4. If the payload_length of a received HeartbeatMessage is too large, the + * received HeartbeatMessage MUST be discarded silently. + */ + return null; + } + + int padding_length = buf.size() - payload.length; + + /* + * RFC 6520 4. The padding of a received HeartbeatMessage message MUST be ignored + */ + return new HeartbeatMessage(type, payload, padding_length); + } + + static class PayloadBuffer extends ByteArrayOutputStream + { + byte[] toTruncatedByteArray(int payloadLength) + { + /* + * RFC 6520 4. The padding_length MUST be at least 16. + */ + int minimumCount = payloadLength + 16; + if (count < minimumCount) + { + return null; + } + return Arrays.copyOf(buf, payloadLength); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HeartbeatMessageType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HeartbeatMessageType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HeartbeatMessageType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HeartbeatMessageType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,15 @@ +package org.bouncycastle.tls; + +/* + * RFC 6520 3. + */ +public class HeartbeatMessageType +{ + public static final short heartbeat_request = 1; + public static final short heartbeat_response = 2; + + public static boolean isValid(short heartbeatMessageType) + { + return heartbeatMessageType >= heartbeat_request && heartbeatMessageType <= heartbeat_response; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HeartbeatMode.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HeartbeatMode.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/HeartbeatMode.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/HeartbeatMode.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,15 @@ +package org.bouncycastle.tls; + +/* + * RFC 6520 + */ +public class HeartbeatMode +{ + public static final short peer_allowed_to_send = 1; + public static final short peer_not_allowed_to_send = 2; + + public static boolean isValid(short heartbeatMode) + { + return heartbeatMode >= peer_allowed_to_send && heartbeatMode <= peer_not_allowed_to_send; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/KeyExchangeAlgorithm.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/KeyExchangeAlgorithm.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/KeyExchangeAlgorithm.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/KeyExchangeAlgorithm.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,52 @@ +package org.bouncycastle.tls; + +/** + * RFC 2246 + *

      + * Note that the values here are implementation-specific and arbitrary. It is recommended not to + * depend on the particular values (e.g. serialization). + */ +public class KeyExchangeAlgorithm +{ + public static final int NULL = 0; + public static final int RSA = 1; + public static final int RSA_EXPORT = 2; + public static final int DHE_DSS = 3; + public static final int DHE_DSS_EXPORT = 4; + public static final int DHE_RSA = 5; + public static final int DHE_RSA_EXPORT = 6; + public static final int DH_DSS = 7; + public static final int DH_DSS_EXPORT = 8; + public static final int DH_RSA = 9; + public static final int DH_RSA_EXPORT = 10; + public static final int DH_anon = 11; + public static final int DH_anon_EXPORT = 12; + + /* + * RFC 4279 + */ + public static final int PSK = 13; + public static final int DHE_PSK = 14; + public static final int RSA_PSK = 15; + + /* + * RFC 4429 + */ + public static final int ECDH_ECDSA = 16; + public static final int ECDHE_ECDSA = 17; + public static final int ECDH_RSA = 18; + public static final int ECDHE_RSA = 19; + public static final int ECDH_anon = 20; + + /* + * RFC 5054 + */ + public static final int SRP = 21; + public static final int SRP_DSS = 22; + public static final int SRP_RSA = 23; + + /* + * RFC 5489 + */ + public static final int ECDHE_PSK = 24; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/MACAlgorithm.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/MACAlgorithm.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/MACAlgorithm.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/MACAlgorithm.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,23 @@ +package org.bouncycastle.tls; + +/** + * RFC 2246 + *

      + * Note that the values here are implementation-specific and arbitrary. It is recommended not to + * depend on the particular values (e.g. serialization). + */ +public class MACAlgorithm +{ + public static final int _null = 0; + public static final int md5 = 1; + public static final int sha = 2; + + /* + * RFC 5246 + */ + public static final int hmac_md5 = md5; + public static final int hmac_sha1 = sha; + public static final int hmac_sha256 = 3; + public static final int hmac_sha384 = 4; + public static final int hmac_sha512 = 5; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/MaxFragmentLength.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/MaxFragmentLength.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/MaxFragmentLength.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/MaxFragmentLength.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,17 @@ +package org.bouncycastle.tls; + +public class MaxFragmentLength +{ + /* + * RFC 3546 3.2. + */ + public static final short pow2_9 = 1; + public static final short pow2_10 = 2; + public static final short pow2_11 = 3; + public static final short pow2_12 = 4; + + public static boolean isValid(short maxFragmentLength) + { + return maxFragmentLength >= pow2_9 && maxFragmentLength <= pow2_12; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/NamedCurve.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/NamedCurve.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/NamedCurve.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/NamedCurve.java 2016-10-10 01:18:58.000000000 +0000 @@ -0,0 +1,222 @@ +package org.bouncycastle.tls; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * RFC 4492 5.1.1 + *

      + * The named curves defined here are those specified in SEC 2 [13]. Note that many of these curves + * are also recommended in ANSI X9.62 [7] and FIPS 186-2 [11]. Values 0xFE00 through 0xFEFF are + * reserved for private use. Values 0xFF01 and 0xFF02 indicate that the client supports arbitrary + * prime and characteristic-2 curves, respectively (the curve parameters must be encoded explicitly + * in ECParameters). + */ +public class NamedCurve +{ + private static final String[] CURVE_NAMES = new String[] { "sect163k1", "sect163r1", "sect163r2", "sect193r1", + "sect193r2", "sect233k1", "sect233r1", "sect239k1", "sect283k1", "sect283r1", "sect409k1", "sect409r1", + "sect571k1", "sect571r1", "secp160k1", "secp160r1", "secp160r2", "secp192k1", "secp192r1", "secp224k1", + "secp224r1", "secp256k1", "secp256r1", "secp384r1", "secp521r1", + "brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1"}; + + public static final int sect163k1 = 1; + public static final int sect163r1 = 2; + public static final int sect163r2 = 3; + public static final int sect193r1 = 4; + public static final int sect193r2 = 5; + public static final int sect233k1 = 6; + public static final int sect233r1 = 7; + public static final int sect239k1 = 8; + public static final int sect283k1 = 9; + public static final int sect283r1 = 10; + public static final int sect409k1 = 11; + public static final int sect409r1 = 12; + public static final int sect571k1 = 13; + public static final int sect571r1 = 14; + public static final int secp160k1 = 15; + public static final int secp160r1 = 16; + public static final int secp160r2 = 17; + public static final int secp192k1 = 18; + public static final int secp192r1 = 19; + public static final int secp224k1 = 20; + public static final int secp224r1 = 21; + public static final int secp256k1 = 22; + public static final int secp256r1 = 23; + public static final int secp384r1 = 24; + public static final int secp521r1 = 25; + + /* + * RFC 7027 + */ + public static final int brainpoolP256r1 = 26; + public static final int brainpoolP384r1 = 27; + public static final int brainpoolP512r1 = 28; + + /* + * reserved (0xFE00..0xFEFF) + */ + + public static final int arbitrary_explicit_prime_curves = 0xFF01; + public static final int arbitrary_explicit_char2_curves = 0xFF02; + + public static final Set ALL; + public static final Set FIPS_APPROVED; + + static + { + Set curves = new HashSet(); + + for (int i = 0; i <= 28; i++) + { + curves.add(i); + } + + curves.add(arbitrary_explicit_prime_curves); + curves.add(arbitrary_explicit_char2_curves); + + ALL = Collections.unmodifiableSet(curves); + + curves = new HashSet(); + + curves.add(secp224k1); + curves.add(secp224r1); + curves.add(secp256k1); + curves.add(secp256r1); + curves.add(secp384r1); + curves.add(secp521r1); + + curves.add(brainpoolP256r1); + curves.add(brainpoolP384r1); + curves.add(brainpoolP512r1); + + FIPS_APPROVED = Collections.unmodifiableSet(curves); + } + + public static int getCurveBits(int namedCurve) + { + switch (namedCurve) + { + case secp160k1: + case secp160r1: + case secp160r2: + return 160; + + case sect163k1: + case sect163r1: + case sect163r2: + return 163; + + case secp192k1: + case secp192r1: + return 192; + + case sect193r1: + case sect193r2: + return 193; + + case secp224k1: + case secp224r1: + return 224; + + case sect233k1: + case sect233r1: + return 233; + + case sect239k1: + return 239; + + case brainpoolP256r1: + case secp256k1: + case secp256r1: + return 256; + + case sect283k1: + case sect283r1: + return 283; + + case brainpoolP384r1: + case secp384r1: + return 384; + + case sect409k1: + case sect409r1: + return 409; + + case brainpoolP512r1: + return 512; + + case secp521r1: + return 521; + + case sect571k1: + case sect571r1: + return 571; + + default: + return 0; + } + } + + public static int getMaximumCurveBits() + { + return 571; + } + + public static String getName(int namedCurve) + { + if (!isValid(namedCurve)) + { + return null; + } + + switch (namedCurve) + { + case arbitrary_explicit_prime_curves: + return "arbitrary_explicit_prime_curves"; + case arbitrary_explicit_char2_curves: + return "arbitrary_explicit_char2_curves"; + default: + return CURVE_NAMES[namedCurve - 1]; + } + } + + public static String getNameOfSpecificCurve(int namedCurve) + { + if (!refersToASpecificNamedCurve(namedCurve)) + { + return null; + } + + return CURVE_NAMES[namedCurve - 1]; + } + + public static boolean isChar2(int namedCurve) + { + return (namedCurve >= sect163k1 && namedCurve <= sect571r1); + } + + public static boolean isPrime(int namedCurve) + { + return (namedCurve >= secp160k1 && namedCurve <= brainpoolP512r1); + } + + public static boolean isValid(int namedCurve) + { + return (namedCurve >= sect163k1 && namedCurve <= brainpoolP512r1) + || (namedCurve >= arbitrary_explicit_prime_curves && namedCurve <= arbitrary_explicit_char2_curves); + } + + public static boolean refersToASpecificNamedCurve(int namedCurve) + { + switch (namedCurve) + { + case arbitrary_explicit_prime_curves: + case arbitrary_explicit_char2_curves: + return false; + default: + return true; + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/NameType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/NameType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/NameType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/NameType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,14 @@ +package org.bouncycastle.tls; + +public class NameType +{ + /* + * RFC 3546 3.1. + */ + public static final short host_name = 0; + + public static boolean isValid(short nameType) + { + return nameType == host_name; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/NewSessionTicket.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/NewSessionTicket.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/NewSessionTicket.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/NewSessionTicket.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,55 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class NewSessionTicket +{ + protected long ticketLifetimeHint; + protected byte[] ticket; + + public NewSessionTicket(long ticketLifetimeHint, byte[] ticket) + { + this.ticketLifetimeHint = ticketLifetimeHint; + this.ticket = ticket; + } + + public long getTicketLifetimeHint() + { + return ticketLifetimeHint; + } + + public byte[] getTicket() + { + return ticket; + } + + /** + * Encode this {@link NewSessionTicket} to an {@link OutputStream}. + * + * @param output the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) + throws IOException + { + TlsUtils.writeUint32(ticketLifetimeHint, output); + TlsUtils.writeOpaque16(ticket, output); + } + + /** + * Parse a {@link NewSessionTicket} from an {@link InputStream}. + * + * @param input the {@link InputStream} to parse from. + * @return a {@link NewSessionTicket} object. + * @throws IOException + */ + public static NewSessionTicket parse(InputStream input) + throws IOException + { + long ticketLifetimeHint = TlsUtils.readUint32(input); + byte[] ticket = TlsUtils.readOpaque16(input); + return new NewSessionTicket(ticketLifetimeHint, ticket); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/OCSPStatusRequest.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/OCSPStatusRequest.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/OCSPStatusRequest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/OCSPStatusRequest.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,132 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ocsp.ResponderID; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.util.io.Streams; + +/** + * RFC 3546 3.6 + */ +public class OCSPStatusRequest +{ + protected Vector responderIDList; + protected Extensions requestExtensions; + + /** + * @param responderIDList + * a {@link Vector} of {@link ResponderID}, specifying the list of trusted OCSP + * responders. An empty list has the special meaning that the responders are + * implicitly known to the server - e.g., by prior arrangement. + * @param requestExtensions + * OCSP request extensions. A null value means that there are no extensions. + */ + public OCSPStatusRequest(Vector responderIDList, Extensions requestExtensions) + { + this.responderIDList = responderIDList; + this.requestExtensions = requestExtensions; + } + + /** + * @return a {@link Vector} of {@link ResponderID} + */ + public Vector getResponderIDList() + { + return responderIDList; + } + + /** + * @return OCSP request extensions + */ + public Extensions getRequestExtensions() + { + return requestExtensions; + } + + /** + * Encode this {@link OCSPStatusRequest} to an {@link OutputStream}. + * + * @param output + * the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) throws IOException + { + if (responderIDList == null || responderIDList.isEmpty()) + { + TlsUtils.writeUint16(0, output); + } + else + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + for (int i = 0; i < responderIDList.size(); ++i) + { + ResponderID responderID = (ResponderID) responderIDList.elementAt(i); + byte[] derEncoding = responderID.getEncoded(ASN1Encoding.DER); + TlsUtils.writeOpaque16(derEncoding, buf); + } + TlsUtils.checkUint16(buf.size()); + TlsUtils.writeUint16(buf.size(), output); + Streams.writeBufTo(buf, output); + } + + if (requestExtensions == null) + { + TlsUtils.writeUint16(0, output); + } + else + { + byte[] derEncoding = requestExtensions.getEncoded(ASN1Encoding.DER); + TlsUtils.checkUint16(derEncoding.length); + TlsUtils.writeUint16(derEncoding.length, output); + output.write(derEncoding); + } + } + + /** + * Parse an {@link OCSPStatusRequest} from an {@link InputStream}. + * + * @param input + * the {@link InputStream} to parse from. + * @return an {@link OCSPStatusRequest} object. + * @throws IOException + */ + public static OCSPStatusRequest parse(InputStream input) throws IOException + { + Vector responderIDList = new Vector(); + { + int length = TlsUtils.readUint16(input); + if (length > 0) + { + byte[] data = TlsUtils.readFully(length, input); + ByteArrayInputStream buf = new ByteArrayInputStream(data); + do + { + byte[] derEncoding = TlsUtils.readOpaque16(buf); + ResponderID responderID = ResponderID.getInstance(TlsUtils.readDERObject(derEncoding)); + responderIDList.addElement(responderID); + } + while (buf.available() > 0); + } + } + + Extensions requestExtensions = null; + { + int length = TlsUtils.readUint16(input); + if (length > 0) + { + byte[] derEncoding = TlsUtils.readFully(length, input); + requestExtensions = Extensions.getInstance(TlsUtils.readDERObject(derEncoding)); + } + } + + return new OCSPStatusRequest(responderIDList, requestExtensions); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/PRFAlgorithm.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/PRFAlgorithm.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/PRFAlgorithm.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/PRFAlgorithm.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,22 @@ +package org.bouncycastle.tls; + +/** + * RFC 5246 + *

      + * Note that the values here are implementation-specific and arbitrary. It is recommended not to + * depend on the particular values (e.g. serialization). + */ +public class PRFAlgorithm +{ + /* + * Placeholder to refer to the legacy TLS algorithm + */ + public static final int tls_prf_legacy = 0; + + public static final int tls_prf_sha256 = 1; + + /* + * Implied by RFC 5288 + */ + public static final int tls_prf_sha384 = 2; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java 2016-11-10 09:53:44.000000000 +0000 @@ -0,0 +1,180 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.util.Strings; + +public final class ProtocolVersion +{ + public static final ProtocolVersion SSLv3 = new ProtocolVersion(0x0300, "SSL 3.0"); + public static final ProtocolVersion TLSv10 = new ProtocolVersion(0x0301, "TLS 1.0"); + public static final ProtocolVersion TLSv11 = new ProtocolVersion(0x0302, "TLS 1.1"); + public static final ProtocolVersion TLSv12 = new ProtocolVersion(0x0303, "TLS 1.2"); + public static final ProtocolVersion DTLSv10 = new ProtocolVersion(0xFEFF, "DTLS 1.0"); + public static final ProtocolVersion DTLSv12 = new ProtocolVersion(0xFEFD, "DTLS 1.2"); + + private int version; + private String name; + + private ProtocolVersion(int v, String name) + { + this.version = v & 0xFFFF; + this.name = name; + } + + public int getFullVersion() + { + return version; + } + + public int getMajorVersion() + { + return version >> 8; + } + + public int getMinorVersion() + { + return version & 0xFF; + } + + public boolean isDTLS() + { + return getMajorVersion() == 0xFE; + } + + public boolean isSSL() + { + return getFullVersion() == SSLv3.getFullVersion(); + } + + public boolean isTLS() + { + return getMajorVersion() == 0x03; + } + + public ProtocolVersion getEquivalentTLSVersion() + { + if (isTLS()) + { + return this; + } + switch (getMinorVersion()) + { + case 0xFF: return TLSv11; + case 0xFD: return TLSv12; + default: return null; + } + } + + public ProtocolVersion getPreviousVersion() throws IOException + { + if (isDTLS()) + { + switch(getMinorVersion()) + { + case 0xFF: return null; + case 0xFD: return DTLSv10; + default : return get(getMajorVersion(), getMinorVersion() + 1); + } + } + else + { + switch (getMinorVersion()) + { + case 0x00: return null; + default : return get(getMajorVersion(), getMinorVersion() - 1); + } + } + } + + public boolean isEqualOrEarlierVersionOf(ProtocolVersion version) + { + if (getMajorVersion() != version.getMajorVersion()) + { + return false; + } + int diffMinorVersion = version.getMinorVersion() - getMinorVersion(); + return isDTLS() ? diffMinorVersion <= 0 : diffMinorVersion >= 0; + } + + public boolean isLaterVersionOf(ProtocolVersion version) + { + if (getMajorVersion() != version.getMajorVersion()) + { + return false; + } + int diffMinorVersion = version.getMinorVersion() - getMinorVersion(); + return isDTLS() ? diffMinorVersion > 0 : diffMinorVersion < 0; + } + + public boolean equals(Object other) + { + return this == other || (other instanceof ProtocolVersion && equals((ProtocolVersion)other)); + } + + public boolean equals(ProtocolVersion other) + { + return other != null && this.version == other.version; + } + + public int hashCode() + { + return version; + } + + public static ProtocolVersion get(int major, int minor) + throws IOException + { + switch (major) + { + case 0x03: + { + switch (minor) + { + case 0x00: + return SSLv3; + case 0x01: + return TLSv10; + case 0x02: + return TLSv11; + case 0x03: + return TLSv12; + } + return getUnknownVersion(major, minor, "TLS"); + } + case 0xFE: + { + switch (minor) + { + case 0xFF: + return DTLSv10; + case 0xFE: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + case 0xFD: + return DTLSv12; + } + return getUnknownVersion(major, minor, "DTLS"); + } + default: + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + public String toString() + { + return name; + } + + private static ProtocolVersion getUnknownVersion(int major, int minor, String prefix) + throws IOException + { + TlsUtils.checkUint8(major); + TlsUtils.checkUint8(minor); + + int v = (major << 8) | minor; + String hex = Strings.toUpperCase(Integer.toHexString(0x10000 | v).substring(1)); + return new ProtocolVersion(v, prefix + " 0x" + hex); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/PSKTlsClient.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/PSKTlsClient.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/PSKTlsClient.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/PSKTlsClient.java 2016-11-18 12:47:10.000000000 +0000 @@ -0,0 +1,90 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.util.Arrays; + +public class PSKTlsClient + extends AbstractTlsClient +{ + // TODO[tls] Perhaps not ideal to keep this in a writable array + protected static final int[] BASE_CIPHER_SUITES = new int[] + { + CipherSuite.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA + }; + + protected TlsDHConfigVerifier dhConfigVerifier; + protected TlsPSKIdentity pskIdentity; + protected int[] supportedCipherSuites; + + // TODO[tls-ops] Need to restore a single-arg constructor here + + public PSKTlsClient(TlsCrypto crypto, TlsPSKIdentity pskIdentity) + { + this(crypto, new DefaultTlsKeyExchangeFactory(), new DefaultTlsDHConfigVerifier(), pskIdentity); + } + + public PSKTlsClient(TlsCrypto crypto, TlsKeyExchangeFactory keyExchangeFactory, TlsDHConfigVerifier dhConfigVerifier, + TlsPSKIdentity pskIdentity) + { + super(crypto, keyExchangeFactory); + + this.dhConfigVerifier = dhConfigVerifier; + this.pskIdentity = pskIdentity; + this.supportedCipherSuites = TlsUtils.getSupportedCipherSuites(crypto, BASE_CIPHER_SUITES); + } + + public int[] getCipherSuites() + { + return Arrays.clone(supportedCipherSuites); + } + + public TlsKeyExchange getKeyExchange() throws IOException + { + int keyExchangeAlgorithm = TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite); + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DHE_PSK: + return createPSKKeyExchange(keyExchangeAlgorithm, dhConfigVerifier, null); + + case KeyExchangeAlgorithm.ECDHE_PSK: + return createPSKKeyExchange(keyExchangeAlgorithm, null, createECConfigVerifier()); + + case KeyExchangeAlgorithm.PSK: + case KeyExchangeAlgorithm.RSA_PSK: + return createPSKKeyExchange(keyExchangeAlgorithm, null, null); + + default: + /* + * Note: internal error here; the TlsProtocol implementation verifies that the + * server-selected cipher suite was in the list of client-offered cipher suites, so if + * we now can't produce an implementation, we shouldn't have offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public TlsAuthentication getAuthentication() throws IOException + { + /* + * Note: This method is not called unless a server certificate is sent, which may be the + * case e.g. for RSA_PSK key exchange. + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected TlsKeyExchange createPSKKeyExchange(int keyExchange, TlsDHConfigVerifier dhConfigVerifier, + TlsECConfigVerifier ecConfigVerifier) throws IOException + { + return keyExchangeFactory.createPSKKeyExchangeClient(keyExchange, supportedSignatureAlgorithms, pskIdentity, + dhConfigVerifier, ecConfigVerifier, clientECPointFormats, serverECPointFormats); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/PSKTlsServer.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/PSKTlsServer.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/PSKTlsServer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/PSKTlsServer.java 2016-11-18 12:47:10.000000000 +0000 @@ -0,0 +1,108 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.util.Arrays; + +public class PSKTlsServer + extends AbstractTlsServer +{ + // TODO[tls] Perhaps not ideal to keep this in a writable array + public static final int[] BASE_CIPHER_SUITES = new int[] + { + CipherSuite.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, + CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, + CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, + CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA + }; + + protected TlsPSKIdentityManager pskIdentityManager; + protected int[] supportedCipherSuites; + + // TODO[tls-ops] Need to restore a single-arg constructor here + + public PSKTlsServer(TlsCrypto crypto, TlsPSKIdentityManager pskIdentityManager) + { + this(crypto, new DefaultTlsKeyExchangeFactory(), pskIdentityManager); + } + + public PSKTlsServer(TlsCrypto crypto, TlsKeyExchangeFactory keyExchangeFactory, TlsPSKIdentityManager pskIdentityManager) + { + super(crypto, keyExchangeFactory); + this.pskIdentityManager = pskIdentityManager; + this.supportedCipherSuites = TlsUtils.getSupportedCipherSuites(crypto, BASE_CIPHER_SUITES); + } + + protected TlsCredentialedDecryptor getRSAEncryptionCredentials() throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected int[] getCipherSuites() + { + return Arrays.clone(supportedCipherSuites); + } + + public TlsCredentials getCredentials() throws IOException + { + int keyExchangeAlgorithm = TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite); + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DHE_PSK: + case KeyExchangeAlgorithm.ECDHE_PSK: + case KeyExchangeAlgorithm.PSK: + return null; + + case KeyExchangeAlgorithm.RSA_PSK: + return getRSAEncryptionCredentials(); + + default: + /* Note: internal error here; selected a key exchange we don't implement! */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public TlsKeyExchange getKeyExchange() throws IOException + { + int keyExchangeAlgorithm = TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite); + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DHE_PSK: + return createPSKKeyExchange(keyExchangeAlgorithm, selectDHConfig(), null); + + case KeyExchangeAlgorithm.ECDHE_PSK: + return createPSKKeyExchange(keyExchangeAlgorithm, null, selectECConfig()); + + case KeyExchangeAlgorithm.PSK: + case KeyExchangeAlgorithm.RSA_PSK: + return createPSKKeyExchange(keyExchangeAlgorithm, null, null); + + default: + /* + * Note: internal error here; the TlsProtocol implementation verifies that the + * server-selected cipher suite was in the list of client-offered cipher suites, so if + * we now can't produce an implementation, we shouldn't have offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + protected TlsKeyExchange createPSKKeyExchange(int keyExchange, TlsDHConfig dhConfig, TlsECConfig ecConfig) throws IOException + { + return keyExchangeFactory.createPSKKeyExchangeServer(keyExchange, supportedSignatureAlgorithms, pskIdentityManager, + dhConfig, ecConfig, serverECPointFormats); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/RecordStream.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/RecordStream.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/RecordStream.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/RecordStream.java 2016-10-28 21:59:53.000000000 +0000 @@ -0,0 +1,369 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsNullNullCipher; + +/** + * An implementation of the TLS 1.0/1.1/1.2 record layer, allowing downgrade to SSLv3. + */ +class RecordStream +{ + private static int DEFAULT_PLAINTEXT_LIMIT = (1 << 14); + static final int TLS_HEADER_SIZE = 5; + static final int TLS_HEADER_TYPE_OFFSET = 0; + static final int TLS_HEADER_VERSION_OFFSET = 1; + static final int TLS_HEADER_LENGTH_OFFSET = 3; + + private TlsProtocol handler; + private InputStream input; + private OutputStream output; + private TlsCompression pendingCompression = null, readCompression = null, writeCompression = null; + private TlsCipher pendingCipher = null, readCipher = null, writeCipher = null; + private long readSeqNo = 0, writeSeqNo = 0; + private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + private TlsHandshakeHash handshakeHash = null; + + private ProtocolVersion readVersion = null, writeVersion = null; + private boolean restrictReadVersion = true; + + private int plaintextLimit, compressedLimit, ciphertextLimit; + + RecordStream(TlsProtocol handler, InputStream input, OutputStream output) + { + this.handler = handler; + this.input = input; + this.output = output; + this.readCompression = new TlsNullCompression(); + this.writeCompression = this.readCompression; + } + + void init(TlsContext context) + { + this.readCipher = new TlsNullNullCipher(); + this.writeCipher = this.readCipher; + this.handshakeHash = new DeferredHash(context); + + setPlaintextLimit(DEFAULT_PLAINTEXT_LIMIT); + } + + int getPlaintextLimit() + { + return plaintextLimit; + } + + void setPlaintextLimit(int plaintextLimit) + { + this.plaintextLimit = plaintextLimit; + this.compressedLimit = this.plaintextLimit + 1024; + this.ciphertextLimit = this.compressedLimit + 1024; + } + + ProtocolVersion getReadVersion() + { + return readVersion; + } + + void setReadVersion(ProtocolVersion readVersion) + { + this.readVersion = readVersion; + } + + void setWriteVersion(ProtocolVersion writeVersion) + { + this.writeVersion = writeVersion; + } + + /** + * RFC 5246 E.1. "Earlier versions of the TLS specification were not fully clear on what the + * record layer version number (TLSPlaintext.version) should contain when sending ClientHello + * (i.e., before it is known which version of the protocol will be employed). Thus, TLS servers + * compliant with this specification MUST accept any value {03,XX} as the record layer version + * number for ClientHello." + */ + void setRestrictReadVersion(boolean enabled) + { + this.restrictReadVersion = enabled; + } + + void setPendingConnectionState(TlsCompression tlsCompression, TlsCipher tlsCipher) + { + this.pendingCompression = tlsCompression; + this.pendingCipher = tlsCipher; + } + + void sentWriteCipherSpec() + throws IOException + { + if (pendingCompression == null || pendingCipher == null) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + this.writeCompression = this.pendingCompression; + this.writeCipher = this.pendingCipher; + this.writeSeqNo = 0; + } + + void receivedReadCipherSpec() + throws IOException + { + if (pendingCompression == null || pendingCipher == null) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + this.readCompression = this.pendingCompression; + this.readCipher = this.pendingCipher; + this.readSeqNo = 0; + } + + void finaliseHandshake() + throws IOException + { + if (readCompression != pendingCompression || writeCompression != pendingCompression + || readCipher != pendingCipher || writeCipher != pendingCipher) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + this.pendingCompression = null; + this.pendingCipher = null; + } + + boolean readRecord() + throws IOException + { + byte[] recordHeader = TlsUtils.readAllOrNothing(TLS_HEADER_SIZE, input); + if (recordHeader == null) + { + return false; + } + + short type = TlsUtils.readUint8(recordHeader, TLS_HEADER_TYPE_OFFSET); + + /* + * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an + * unexpected_message alert. + */ + checkType(type, AlertDescription.unexpected_message); + + if (!restrictReadVersion) + { + int version = TlsUtils.readVersionRaw(recordHeader, TLS_HEADER_VERSION_OFFSET); + if ((version & 0xffffff00) != 0x0300) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + else + { + ProtocolVersion version = TlsUtils.readVersion(recordHeader, TLS_HEADER_VERSION_OFFSET); + if (readVersion == null) + { + readVersion = version; + } + else if (!version.equals(readVersion)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + + int length = TlsUtils.readUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET); + byte[] plaintext = decodeAndVerify(type, input, length); + handler.processRecord(type, plaintext, 0, plaintext.length); + return true; + } + + byte[] decodeAndVerify(short type, InputStream input, int len) + throws IOException + { + checkLength(len, ciphertextLimit, AlertDescription.record_overflow); + + byte[] buf = TlsUtils.readFully(len, input); + byte[] decoded = readCipher.decodeCiphertext(readSeqNo++, type, buf, 0, buf.length); + + checkLength(decoded.length, compressedLimit, AlertDescription.record_overflow); + + /* + * TODO RFC5264 6.2.2. Implementation note: Decompression functions are responsible for + * ensuring that messages cannot cause internal buffer overflows. + */ + OutputStream cOut = readCompression.decompress(buffer); + if (cOut != buffer) + { + cOut.write(decoded, 0, decoded.length); + cOut.flush(); + decoded = getBufferContents(); + } + + /* + * RFC 5264 6.2.2. If the decompression function encounters a TLSCompressed.fragment that + * would decompress to a length in excess of 2^14 bytes, it should report a fatal + * decompression failure error. + */ + checkLength(decoded.length, plaintextLimit, AlertDescription.decompression_failure); + + /* + * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert, + * or ChangeCipherSpec content types. + */ + if (decoded.length < 1 && type != ContentType.application_data) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + return decoded; + } + + void writeRecord(short type, byte[] plaintext, int plaintextOffset, int plaintextLength) + throws IOException + { + // Never send anything until a valid ClientHello has been received + if (writeVersion == null) + { + return; + } + + /* + * RFC 5264 6. Implementations MUST NOT send record types not defined in this document + * unless negotiated by some extension. + */ + checkType(type, AlertDescription.internal_error); + + /* + * RFC 5264 6.2.1 The length should not exceed 2^14. + */ + checkLength(plaintextLength, plaintextLimit, AlertDescription.internal_error); + + /* + * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert, + * or ChangeCipherSpec content types. + */ + if (plaintextLength < 1 && type != ContentType.application_data) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + if (type == ContentType.handshake) + { + updateHandshakeData(plaintext, plaintextOffset, plaintextLength); + } + + OutputStream cOut = writeCompression.compress(buffer); + + byte[] ciphertext; + if (cOut == buffer) + { + ciphertext = writeCipher.encodePlaintext(writeSeqNo++, type, plaintext, plaintextOffset, plaintextLength); + } + else + { + cOut.write(plaintext, plaintextOffset, plaintextLength); + cOut.flush(); + byte[] compressed = getBufferContents(); + + /* + * RFC5264 6.2.2. Compression must be lossless and may not increase the content length + * by more than 1024 bytes. + */ + checkLength(compressed.length, plaintextLength + 1024, AlertDescription.internal_error); + + ciphertext = writeCipher.encodePlaintext(writeSeqNo++, type, compressed, 0, compressed.length); + } + + /* + * RFC 5264 6.2.3. The length may not exceed 2^14 + 2048. + */ + checkLength(ciphertext.length, ciphertextLimit, AlertDescription.internal_error); + + byte[] record = new byte[ciphertext.length + TLS_HEADER_SIZE]; + TlsUtils.writeUint8(type, record, TLS_HEADER_TYPE_OFFSET); + TlsUtils.writeVersion(writeVersion, record, TLS_HEADER_VERSION_OFFSET); + TlsUtils.writeUint16(ciphertext.length, record, TLS_HEADER_LENGTH_OFFSET); + System.arraycopy(ciphertext, 0, record, TLS_HEADER_SIZE, ciphertext.length); + output.write(record); + output.flush(); + } + + void notifyHelloComplete() + { + this.handshakeHash = handshakeHash.notifyPRFDetermined(); + } + + TlsHandshakeHash getHandshakeHash() + { + return handshakeHash; + } + + TlsHandshakeHash prepareToFinish() + { + TlsHandshakeHash result = handshakeHash; + this.handshakeHash = handshakeHash.stopTracking(); + return result; + } + + void updateHandshakeData(byte[] message, int offset, int len) + { + handshakeHash.update(message, offset, len); + } + + void safeClose() + { + try + { + input.close(); + } + catch (IOException e) + { + } + + try + { + output.close(); + } + catch (IOException e) + { + } + } + + void flush() + throws IOException + { + output.flush(); + } + + private byte[] getBufferContents() + { + byte[] contents = buffer.toByteArray(); + buffer.reset(); + return contents; + } + + private static void checkType(short type, short alertDescription) + throws IOException + { + switch (type) + { + case ContentType.application_data: + case ContentType.alert: + case ContentType.change_cipher_spec: + case ContentType.handshake: + case ContentType.heartbeat: + break; + default: + throw new TlsFatalAlert(alertDescription); + } + } + + private static void checkLength(int length, int limit, short alertDescription) + throws IOException + { + if (length > limit) + { + throw new TlsFatalAlert(alertDescription); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SecurityParameters.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SecurityParameters.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SecurityParameters.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SecurityParameters.java 2016-10-04 07:14:20.000000000 +0000 @@ -0,0 +1,129 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsSecret; + +public class SecurityParameters +{ + int entity = -1; + int cipherSuite = -1; + short compressionAlgorithm = CompressionMethod._null; + short maxFragmentLength = -1; + int prfAlgorithm = -1; + int verifyDataLength = -1; + TlsSecret masterSecret = null; + byte[] clientRandom = null; + byte[] serverRandom = null; + byte[] sessionHash = null; + byte[] pskIdentity = null; + byte[] srpIdentity = null; + boolean encryptThenMAC = false; + boolean extendedMasterSecret = false; + boolean truncatedHMac = false; + + void clear() + { + if (this.masterSecret != null) + { + this.masterSecret.destroy(); + this.masterSecret = null; + } + } + + /** + * @return {@link ConnectionEnd} + */ + public int getEntity() + { + return entity; + } + + /** + * @return {@link CipherSuite} + */ + public int getCipherSuite() + { + return cipherSuite; + } + + /** + * @return {@link CompressionMethod} + */ + public short getCompressionAlgorithm() + { + return compressionAlgorithm; + } + + /** + * @return {@link MaxFragmentLength}, or -1 if none + */ + public short getMaxFragmentLength() + { + return maxFragmentLength; + } + + /** + * @return {@link PRFAlgorithm} + */ + public int getPrfAlgorithm() + { + return prfAlgorithm; + } + + public int getVerifyDataLength() + { + return verifyDataLength; + } + + public TlsSecret getMasterSecret() + { + return masterSecret; + } + + public byte[] getClientRandom() + { + return clientRandom; + } + + public byte[] getServerRandom() + { + return serverRandom; + } + + public byte[] getSessionHash() + { + return sessionHash; + } + + /** + * @deprecated Use {@link SecurityParameters#getPSKIdentity()} + */ + public byte[] getPskIdentity() + { + return pskIdentity; + } + + public byte[] getPSKIdentity() + { + return pskIdentity; + } + + public byte[] getSRPIdentity() + { + return srpIdentity; + } + + public boolean isEncryptThenMAC() + { + return encryptThenMAC; + } + + public boolean isExtendedMasterSecret() + { + return extendedMasterSecret; + } + + public boolean isTruncatedHMac() + { + return truncatedHMac; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ServerName.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ServerName.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ServerName.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ServerName.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,110 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class ServerName +{ + protected short nameType; + protected Object name; + + public ServerName(short nameType, Object name) + { + if (!isCorrectType(nameType, name)) + { + throw new IllegalArgumentException("'name' is not an instance of the correct type"); + } + + this.nameType = nameType; + this.name = name; + } + + public short getNameType() + { + return nameType; + } + + public Object getName() + { + return name; + } + + public String getHostName() + { + if (!isCorrectType(NameType.host_name, name)) + { + throw new IllegalStateException("'name' is not a HostName string"); + } + return (String)name; + } + + /** + * Encode this {@link ServerName} to an {@link OutputStream}. + * + * @param output + * the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) throws IOException + { + TlsUtils.writeUint8(nameType, output); + + switch (nameType) + { + case NameType.host_name: + byte[] asciiEncoding = ((String)name).getBytes("ASCII"); + if (asciiEncoding.length < 1) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + TlsUtils.writeOpaque16(asciiEncoding, output); + break; + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + /** + * Parse a {@link ServerName} from an {@link InputStream}. + * + * @param input + * the {@link InputStream} to parse from. + * @return a {@link ServerName} object. + * @throws IOException + */ + public static ServerName parse(InputStream input) throws IOException + { + short name_type = TlsUtils.readUint8(input); + Object name; + + switch (name_type) + { + case NameType.host_name: + { + byte[] asciiEncoding = TlsUtils.readOpaque16(input); + if (asciiEncoding.length < 1) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + name = new String(asciiEncoding, "ASCII"); + break; + } + default: + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + return new ServerName(name_type, name); + } + + protected static boolean isCorrectType(short nameType, Object name) + { + switch (nameType) + { + case NameType.host_name: + return name instanceof String; + default: + throw new IllegalArgumentException("'name' is an unsupported value"); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ServerNameList.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ServerNameList.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ServerNameList.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ServerNameList.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,118 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.io.Streams; + +public class ServerNameList +{ + protected Vector serverNameList; + + /** + * @param serverNameList a {@link Vector} of {@link ServerName}. + */ + public ServerNameList(Vector serverNameList) + { + if (serverNameList == null) + { + throw new IllegalArgumentException("'serverNameList' must not be null"); + } + + this.serverNameList = serverNameList; + } + + /** + * @return a {@link Vector} of {@link ServerName}. + */ + public Vector getServerNameList() + { + return serverNameList; + } + + /** + * Encode this {@link ServerNameList} to an {@link OutputStream}. + * + * @param output + * the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + short[] nameTypesSeen = new short[0]; + for (int i = 0; i < serverNameList.size(); ++i) + { + ServerName entry = (ServerName)serverNameList.elementAt(i); + + nameTypesSeen = checkNameType(nameTypesSeen, entry.getNameType()); + if (nameTypesSeen == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + entry.encode(buf); + } + + TlsUtils.checkUint16(buf.size()); + TlsUtils.writeUint16(buf.size(), output); + Streams.writeBufTo(buf, output); + } + + /** + * Parse a {@link ServerNameList} from an {@link InputStream}. + * + * @param input + * the {@link InputStream} to parse from. + * @return a {@link ServerNameList} object. + * @throws IOException + */ + public static ServerNameList parse(InputStream input) throws IOException + { + int length = TlsUtils.readUint16(input); + if (length < 1) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + byte[] data = TlsUtils.readFully(length, input); + + ByteArrayInputStream buf = new ByteArrayInputStream(data); + + short[] nameTypesSeen = new short[0]; + Vector server_name_list = new Vector(); + while (buf.available() > 0) + { + ServerName entry = ServerName.parse(buf); + + nameTypesSeen = checkNameType(nameTypesSeen, entry.getNameType()); + if (nameTypesSeen == null) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + server_name_list.addElement(entry); + } + + return new ServerNameList(server_name_list); + } + + private static short[] checkNameType(short[] nameTypesSeen, short nameType) + { + /* + * RFC 6066 3. The ServerNameList MUST NOT contain more than one name of the same + * name_type. + */ + if (!NameType.isValid(nameType) || Arrays.contains(nameTypesSeen, nameType)) + { + return null; + } + return Arrays.append(nameTypesSeen, nameType); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ServerOnlyTlsAuthentication.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ServerOnlyTlsAuthentication.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ServerOnlyTlsAuthentication.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ServerOnlyTlsAuthentication.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,10 @@ +package org.bouncycastle.tls; + +public abstract class ServerOnlyTlsAuthentication + implements TlsAuthentication +{ + public final TlsCredentials getClientCredentials(CertificateRequest certificateRequest) + { + return null; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ServerSRPParams.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ServerSRPParams.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/ServerSRPParams.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/ServerSRPParams.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,75 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; + +import org.bouncycastle.util.Arrays; + +public class ServerSRPParams +{ + protected BigInteger N, g, B; + protected byte[] s; + + public ServerSRPParams(BigInteger N, BigInteger g, byte[] s, BigInteger B) + { + this.N = N; + this.g = g; + this.s = Arrays.clone(s); + this.B = B; + } + + public BigInteger getB() + { + return B; + } + + public BigInteger getG() + { + return g; + } + + public BigInteger getN() + { + return N; + } + + public byte[] getS() + { + return s; + } + + /** + * Encode this {@link ServerSRPParams} to an {@link OutputStream}. + * + * @param output + * the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) throws IOException + { + TlsSRPUtils.writeSRPParameter(N, output); + TlsSRPUtils.writeSRPParameter(g, output); + TlsUtils.writeOpaque8(s, output); + TlsSRPUtils.writeSRPParameter(B, output); + } + + /** + * Parse a {@link ServerSRPParams} from an {@link InputStream}. + * + * @param input + * the {@link InputStream} to parse from. + * @return a {@link ServerSRPParams} object. + * @throws IOException + */ + public static ServerSRPParams parse(InputStream input) throws IOException + { + BigInteger N = TlsSRPUtils.readSRPParameter(input); + BigInteger g = TlsSRPUtils.readSRPParameter(input); + byte[] s = TlsUtils.readOpaque8(input); + BigInteger B = TlsSRPUtils.readSRPParameter(input); + + return new ServerSRPParams(N, g, s, B); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SessionID.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SessionID.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SessionID.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SessionID.java 2016-09-15 00:36:52.000000000 +0000 @@ -0,0 +1,45 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + +public final class SessionID + implements Comparable +{ + private final byte[] id; + + public SessionID(byte[] id) + { + this.id = Arrays.clone(id); + } + + public int compareTo(Object o) + { + return Arrays.compareUnsigned(id, ((SessionID)o).id); + } + + public boolean equals(Object obj) + { + if (!(obj instanceof SessionID)) + { + return false; + } + SessionID other = (SessionID)obj; + return Arrays.areEqual(id, other.id); + } + + public byte[] getBytes() + { + return Arrays.clone(id); + } + + public int hashCode() + { + return Arrays.hashCode(id); + } + + public String toString() + { + return Hex.toHexString(id); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SessionParameters.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SessionParameters.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SessionParameters.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SessionParameters.java 2016-11-21 00:44:31.000000000 +0000 @@ -0,0 +1,216 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Hashtable; + +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.Arrays; + +public final class SessionParameters +{ + public static final class Builder + { + private int cipherSuite = -1; + private short compressionAlgorithm = -1; + private Certificate localCertificate = null; + private TlsSecret masterSecret = null; + private ProtocolVersion negotiatedVersion; + private Certificate peerCertificate = null; + private byte[] pskIdentity = null; + private byte[] srpIdentity = null; + private byte[] encodedServerExtensions = null; + + public Builder() + { + } + + public SessionParameters build() + { + validate(this.cipherSuite >= 0, "cipherSuite"); + validate(this.compressionAlgorithm >= 0, "compressionAlgorithm"); + validate(this.masterSecret != null, "masterSecret"); + return new SessionParameters(cipherSuite, compressionAlgorithm, localCertificate, masterSecret, + negotiatedVersion, peerCertificate, pskIdentity, srpIdentity, encodedServerExtensions); + } + + public Builder setCipherSuite(int cipherSuite) + { + this.cipherSuite = cipherSuite; + return this; + } + + public Builder setCompressionAlgorithm(short compressionAlgorithm) + { + this.compressionAlgorithm = compressionAlgorithm; + return this; + } + + public Builder setLocalCertificate(Certificate localCertificate) + { + this.localCertificate = localCertificate; + return this; + } + + public Builder setMasterSecret(TlsSecret masterSecret) + { + this.masterSecret = masterSecret; + return this; + } + + public Builder setNegotiatedVersion(ProtocolVersion negotiatedVersion) + { + this.negotiatedVersion = negotiatedVersion; + return this; + } + + public Builder setPeerCertificate(Certificate peerCertificate) + { + this.peerCertificate = peerCertificate; + return this; + } + + /** + * @deprecated Use {@link #setPSKIdentity(byte[])} + */ + public Builder setPskIdentity(byte[] pskIdentity) + { + this.pskIdentity = pskIdentity; + return this; + } + + public Builder setPSKIdentity(byte[] pskIdentity) + { + this.pskIdentity = pskIdentity; + return this; + } + + public Builder setSRPIdentity(byte[] srpIdentity) + { + this.srpIdentity = srpIdentity; + return this; + } + + public Builder setServerExtensions(Hashtable serverExtensions) throws IOException + { + if (serverExtensions == null) + { + encodedServerExtensions = null; + } + else + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + TlsProtocol.writeExtensions(buf, serverExtensions); + encodedServerExtensions = buf.toByteArray(); + } + return this; + } + + private void validate(boolean condition, String parameter) + { + if (!condition) + { + throw new IllegalStateException("Required session parameter '" + parameter + "' not configured"); + } + } + } + + private int cipherSuite; + private short compressionAlgorithm; + private Certificate localCertificate; + private TlsSecret masterSecret; + private ProtocolVersion negotiatedVersion; + private Certificate peerCertificate; + private byte[] pskIdentity = null; + private byte[] srpIdentity = null; + private byte[] encodedServerExtensions; + + private SessionParameters(int cipherSuite, short compressionAlgorithm, Certificate localCertificate, + TlsSecret masterSecret, ProtocolVersion negotiatedVersion, Certificate peerCertificate, byte[] pskIdentity, + byte[] srpIdentity, byte[] encodedServerExtensions) + { + this.cipherSuite = cipherSuite; + this.compressionAlgorithm = compressionAlgorithm; + this.localCertificate = localCertificate; + this.masterSecret = masterSecret; + this.negotiatedVersion = negotiatedVersion; + this.peerCertificate = peerCertificate; + this.pskIdentity = Arrays.clone(pskIdentity); + this.srpIdentity = Arrays.clone(srpIdentity); + this.encodedServerExtensions = encodedServerExtensions; + } + + public void clear() + { + if (this.masterSecret != null) + { + this.masterSecret.destroy(); + } + } + + public SessionParameters copy() + { + return new SessionParameters(cipherSuite, compressionAlgorithm, localCertificate, masterSecret, + negotiatedVersion, peerCertificate, pskIdentity, srpIdentity, encodedServerExtensions); + } + + public int getCipherSuite() + { + return cipherSuite; + } + + public short getCompressionAlgorithm() + { + return compressionAlgorithm; + } + + public Certificate getLocalCertificate() + { + return localCertificate; + } + + public TlsSecret getMasterSecret() + { + return masterSecret; + } + + public ProtocolVersion getNegotiatedVersion() + { + return negotiatedVersion; + } + + public Certificate getPeerCertificate() + { + return peerCertificate; + } + + /** + * @deprecated Use {@link #getPSKIdentity()} + */ + public byte[] getPskIdentity() + { + return pskIdentity; + } + + public byte[] getPSKIdentity() + { + return pskIdentity; + } + + public byte[] getSRPIdentity() + { + return srpIdentity; + } + + public Hashtable readServerExtensions() throws IOException + { + if (encodedServerExtensions == null) + { + return null; + } + + ByteArrayInputStream buf = new ByteArrayInputStream(encodedServerExtensions); + return TlsProtocol.readExtensions(buf); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,12 @@ +package org.bouncycastle.tls; + +/** + * RFC 5246 7.4.1.4.1 (in RFC 2246, there were no specific values assigned) + */ +public class SignatureAlgorithm +{ + public static final short anonymous = 0; + public static final short rsa = 1; + public static final short dsa = 2; + public static final short ecdsa = 3; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,96 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * RFC 5246 7.4.1.4.1 + */ +public class SignatureAndHashAlgorithm +{ + protected short hash; + protected short signature; + + /** + * @param hash {@link HashAlgorithm} + * @param signature {@link SignatureAlgorithm} + */ + public SignatureAndHashAlgorithm(short hash, short signature) + { + if (!TlsUtils.isValidUint8(hash)) + { + throw new IllegalArgumentException("'hash' should be a uint8"); + } + if (!TlsUtils.isValidUint8(signature)) + { + throw new IllegalArgumentException("'signature' should be a uint8"); + } + if (signature == SignatureAlgorithm.anonymous) + { + throw new IllegalArgumentException("'signature' MUST NOT be \"anonymous\""); + } + + this.hash = hash; + this.signature = signature; + } + + /** + * @return {@link HashAlgorithm} + */ + public short getHash() + { + return hash; + } + + /** + * @return {@link SignatureAlgorithm} + */ + public short getSignature() + { + return signature; + } + + public boolean equals(Object obj) + { + if (!(obj instanceof SignatureAndHashAlgorithm)) + { + return false; + } + SignatureAndHashAlgorithm other = (SignatureAndHashAlgorithm)obj; + return other.getHash() == getHash() && other.getSignature() == getSignature(); + } + + public int hashCode() + { + return (getHash() << 16) | getSignature(); + } + + /** + * Encode this {@link SignatureAndHashAlgorithm} to an {@link OutputStream}. + * + * @param output the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) + throws IOException + { + TlsUtils.writeUint8(getHash(), output); + TlsUtils.writeUint8(getSignature(), output); + } + + /** + * Parse a {@link SignatureAndHashAlgorithm} from an {@link InputStream}. + * + * @param input the {@link InputStream} to parse from. + * @return a {@link SignatureAndHashAlgorithm} object. + * @throws IOException + */ + public static SignatureAndHashAlgorithm parse(InputStream input) + throws IOException + { + short hash = TlsUtils.readUint8(input); + short signature = TlsUtils.readUint8(input); + return new SignatureAndHashAlgorithm(hash, signature); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SimulatedTlsSRPIdentityManager.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SimulatedTlsSRPIdentityManager.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SimulatedTlsSRPIdentityManager.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SimulatedTlsSRPIdentityManager.java 2016-10-01 23:50:13.000000000 +0000 @@ -0,0 +1,74 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.math.BigInteger; + +import org.bouncycastle.tls.crypto.SRP6Group; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsHMAC; +import org.bouncycastle.tls.crypto.TlsSRP6VerifierGenerator; +import org.bouncycastle.tls.crypto.TlsSRPConfig; +import org.bouncycastle.util.Strings; + +/** + * An implementation of {@link TlsSRPIdentityManager} that simulates the existence of "unknown" identities + * to obscure the fact that there is no verifier for them. + */ +public class SimulatedTlsSRPIdentityManager + implements TlsSRPIdentityManager +{ + private static final byte[] PREFIX_PASSWORD = Strings.toByteArray("password"); + private static final byte[] PREFIX_SALT = Strings.toByteArray("salt"); + + /** + * Create a {@link SimulatedTlsSRPIdentityManager} that implements the algorithm from RFC 5054 2.5.1.3 + * + * @param group the {@link SRP6Group} defining the group that SRP is operating in + * @param seedKey the secret "seed key" referred to in RFC 5054 2.5.1.3 + * @return an instance of {@link SimulatedTlsSRPIdentityManager} + */ + public static SimulatedTlsSRPIdentityManager getRFC5054Default(TlsCrypto crypto, SRP6Group group, byte[] seedKey) + throws IOException + { + TlsHMAC mac = crypto.createHMAC(MACAlgorithm.hmac_sha1); + + mac.setKey(seedKey); + + TlsSRPConfig srpConfig = new TlsSRPConfig(); + + srpConfig.setExplicitNG(new BigInteger[] { group.getN(), group.getG() }); + + return new SimulatedTlsSRPIdentityManager(group, crypto.createSRP6VerifierGenerator(srpConfig), mac); + } + + protected SRP6Group group; + protected TlsSRP6VerifierGenerator verifierGenerator; + protected TlsHMAC mac; + + public SimulatedTlsSRPIdentityManager(SRP6Group group, TlsSRP6VerifierGenerator verifierGenerator, TlsHMAC mac) + { + this.group = group; + this.verifierGenerator = verifierGenerator; + this.mac = mac; + } + + public TlsSRPLoginParameters getLoginParameters(byte[] identity) + { + mac.update(PREFIX_SALT, 0, PREFIX_SALT.length); + mac.update(identity, 0, identity.length); + + byte[] salt = mac.calculateMAC(); + + mac.update(PREFIX_PASSWORD, 0, PREFIX_PASSWORD.length); + mac.update(identity, 0, identity.length); + + byte[] password = mac.calculateMAC(); + + BigInteger verifier = verifierGenerator.generateVerifier(salt, identity, password); + + TlsSRPConfig srpConfig = new TlsSRPConfig(); + srpConfig.setExplicitNG(new BigInteger[]{ group.getN(), group.getG() }); + + return new TlsSRPLoginParameters(srpConfig, verifier, salt); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SRPTlsClient.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SRPTlsClient.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SRPTlsClient.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SRPTlsClient.java 2016-11-18 12:47:10.000000000 +0000 @@ -0,0 +1,112 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.util.Hashtable; + +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.util.Arrays; + +public class SRPTlsClient + extends AbstractTlsClient +{ + // TODO[tls] Perhaps not ideal to keep this in a writable array + public static final int[] BASE_CIPHER_SUITES = new int[] + { + CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA + }; + + protected TlsSRPConfigVerifier srpConfigVerifier; + + protected byte[] identity; + protected byte[] password; + + protected int[] supportedCipherSuites; + + // TODO[tls-ops] Need to restore a single-arg constructor here + + public SRPTlsClient(TlsCrypto crypto, byte[] identity, byte[] password) + { + this(crypto, new DefaultTlsKeyExchangeFactory(), new DefaultTlsSRPConfigVerifier(), identity, password); + } + + public SRPTlsClient(TlsCrypto crypto, TlsKeyExchangeFactory keyExchangeFactory, TlsSRPConfigVerifier srpConfigVerifier, + byte[] identity, byte[] password) + { + super(crypto, keyExchangeFactory); + this.srpConfigVerifier = srpConfigVerifier; + this.identity = Arrays.clone(identity); + this.password = Arrays.clone(password); + this.supportedCipherSuites = TlsUtils.getSupportedCipherSuites(crypto, BASE_CIPHER_SUITES); + } + + protected boolean requireSRPServerExtension() + { + // No explicit guidance in RFC 5054; by default an (empty) extension from server is optional + return false; + } + + public int[] getCipherSuites() + { + return Arrays.clone(supportedCipherSuites); + } + + public Hashtable getClientExtensions() + throws IOException + { + Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions()); + TlsSRPUtils.addSRPExtension(clientExtensions, this.identity); + return clientExtensions; + } + + public void processServerExtensions(Hashtable serverExtensions) + throws IOException + { + if (!TlsUtils.hasExpectedEmptyExtensionData(serverExtensions, TlsSRPUtils.EXT_SRP, + AlertDescription.illegal_parameter)) + { + if (requireSRPServerExtension()) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + + super.processServerExtensions(serverExtensions); + } + + public TlsKeyExchange getKeyExchange() + throws IOException + { + int keyExchangeAlgorithm = TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite); + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.SRP: + case KeyExchangeAlgorithm.SRP_DSS: + case KeyExchangeAlgorithm.SRP_RSA: + return createSRPKeyExchange(keyExchangeAlgorithm); + + default: + /* + * Note: internal error here; the TlsProtocol implementation verifies that the + * server-selected cipher suite was in the list of client-offered cipher suites, so if + * we now can't produce an implementation, we shouldn't have offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public TlsAuthentication getAuthentication() throws IOException + { + /* + * Note: This method is not called unless a server certificate is sent, which may be the + * case e.g. for SRP_DSS or SRP_RSA key exchange. + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected TlsKeyExchange createSRPKeyExchange(int keyExchange) throws IOException + { + return keyExchangeFactory.createSRPKeyExchangeClient(keyExchange, supportedSignatureAlgorithms, + srpConfigVerifier, identity, password); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SRPTlsServer.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SRPTlsServer.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SRPTlsServer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SRPTlsServer.java 2016-11-18 12:47:10.000000000 +0000 @@ -0,0 +1,134 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.util.Hashtable; + +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.util.Arrays; + +public class SRPTlsServer + extends AbstractTlsServer +{ + // TODO[tls] Perhaps not ideal to keep this in a writable array + public static final int[] BASE_CIPHER_SUITES = new int[] + { + CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA + }; + + protected TlsSRPIdentityManager srpIdentityManager; + protected int[] supportedCipherSuites; + + protected byte[] srpIdentity = null; + protected TlsSRPLoginParameters loginParameters = null; + + // TODO[tls-ops] Need to restore a single-arg constructor here + + public SRPTlsServer(TlsCrypto crypto, TlsSRPIdentityManager srpIdentityManager) + { + this(crypto, new DefaultTlsKeyExchangeFactory(), srpIdentityManager); + } + + public SRPTlsServer(TlsCrypto crypto, TlsKeyExchangeFactory keyExchangeFactory, TlsSRPIdentityManager srpIdentityManager) + { + super(crypto, keyExchangeFactory); + this.srpIdentityManager = srpIdentityManager; + this.supportedCipherSuites = TlsUtils.getSupportedCipherSuites(crypto, BASE_CIPHER_SUITES); + } + + protected TlsCredentialedSigner getDSASignerCredentials() + throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected TlsCredentialedSigner getRSASignerCredentials() + throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected int[] getCipherSuites() + { + return Arrays.clone(supportedCipherSuites); + } + + public void processClientExtensions(Hashtable clientExtensions) throws IOException + { + super.processClientExtensions(clientExtensions); + + this.srpIdentity = TlsSRPUtils.getSRPExtension(clientExtensions); + } + + public int getSelectedCipherSuite() throws IOException + { + int cipherSuite = super.getSelectedCipherSuite(); + + if (TlsSRPUtils.isSRPCipherSuite(cipherSuite)) + { + if (srpIdentity != null) + { + this.loginParameters = srpIdentityManager.getLoginParameters(srpIdentity); + } + + if (loginParameters == null) + { + throw new TlsFatalAlert(AlertDescription.unknown_psk_identity); + } + } + + return cipherSuite; + } + + public TlsCredentials getCredentials() throws IOException + { + int keyExchangeAlgorithm = TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite); + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.SRP: + return null; + + case KeyExchangeAlgorithm.SRP_DSS: + return getDSASignerCredentials(); + + case KeyExchangeAlgorithm.SRP_RSA: + return getRSASignerCredentials(); + + default: + /* Note: internal error here; selected a key exchange we don't implement! */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public TlsKeyExchange getKeyExchange() + throws IOException + { + int keyExchangeAlgorithm = TlsUtils.getKeyExchangeAlgorithm(selectedCipherSuite); + + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.SRP: + case KeyExchangeAlgorithm.SRP_DSS: + case KeyExchangeAlgorithm.SRP_RSA: + return createSRPKeyExchange(keyExchangeAlgorithm); + + default: + /* + * Note: internal error here; the TlsProtocol implementation verifies that the + * server-selected cipher suite was in the list of client-offered cipher suites, so if + * we now can't produce an implementation, we shouldn't have offered it! + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + protected TlsKeyExchange createSRPKeyExchange(int keyExchange) throws IOException + { + return keyExchangeFactory.createSRPKeyExchangeServer(keyExchange, supportedSignatureAlgorithms, srpIdentity, loginParameters); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SRTPProtectionProfile.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SRTPProtectionProfile.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SRTPProtectionProfile.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SRTPProtectionProfile.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,18 @@ +package org.bouncycastle.tls; + +public class SRTPProtectionProfile +{ + /* + * RFC 5764 4.1.2. + */ + public static final int SRTP_AES128_CM_HMAC_SHA1_80 = 0x0001; + public static final int SRTP_AES128_CM_HMAC_SHA1_32 = 0x0002; + public static final int SRTP_NULL_HMAC_SHA1_80 = 0x0005; + public static final int SRTP_NULL_HMAC_SHA1_32 = 0x0006; + + /* + * RFC 7714 14.2. + */ + public static final int SRTP_AEAD_AES_128_GCM = 0x0007; + public static final int SRTP_AEAD_AES_256_GCM = 0x0008; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SSL3Constants.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SSL3Constants.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SSL3Constants.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SSL3Constants.java 2016-08-28 04:49:25.000000000 +0000 @@ -0,0 +1,29 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.util.Arrays; + +public class SSL3Constants +{ + private static final byte IPAD_BYTE = (byte)0x36; + private static final byte OPAD_BYTE = (byte)0x5C; + + private static byte[] genPad(byte b, int count) + { + byte[] padding = new byte[count]; + Arrays.fill(padding, b); + return padding; + } + + private static final byte[] IPAD = genPad(IPAD_BYTE, 48); + private static final byte[] OPAD = genPad(OPAD_BYTE, 48); + + public static byte[] getInputPad() + { + return IPAD.clone(); + } + + public static byte[] getOutputPad() + { + return OPAD.clone(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SupplementalDataEntry.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SupplementalDataEntry.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SupplementalDataEntry.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SupplementalDataEntry.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,23 @@ +package org.bouncycastle.tls; + +public class SupplementalDataEntry +{ + protected int dataType; + protected byte[] data; + + public SupplementalDataEntry(int dataType, byte[] data) + { + this.dataType = dataType; + this.data = data; + } + + public int getDataType() + { + return dataType; + } + + public byte[] getData() + { + return data; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SupplementalDataType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SupplementalDataType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/SupplementalDataType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/SupplementalDataType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,12 @@ +package org.bouncycastle.tls; + +/** + * RFC 4680 + */ +public class SupplementalDataType +{ + /* + * RFC 4681 + */ + public static final int user_mapping_data = 0; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsAuthentication.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsAuthentication.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsAuthentication.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsAuthentication.java 2016-11-22 03:46:01.000000000 +0000 @@ -0,0 +1,38 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedAgreement; +import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedDecryptor; + +/** + * Base interface to provide TLS authentication credentials. + */ +public interface TlsAuthentication +{ + /** + * Called by the protocol handler to report the server certificate + * Note: this method is responsible for certificate verification and validation + * + * @param serverCertificate the server certificate received + * @throws IOException + */ + void notifyServerCertificate(Certificate serverCertificate) + throws IOException; + + /** + * Return client credentials in response to server's certificate request. The returned value may + * be null, or else it MUST implement exactly one of {@link TlsCredentialedAgreement}, + * {@link TlsCredentialedDecryptor}, or {@link TlsCredentialedSigner}, depending on the key + * exchange that was negotiated and the details of the {@link CertificateRequest}. + * + * @see {@link BcDefaultTlsCredentialedAgreement}, {@link BcDefaultTlsCredentialedDecryptor} + * + * @param certificateRequest + * details of the certificate request + * @return a TlsCredentials object or null for no client authentication + * @throws IOException + */ + TlsCredentials getClientCredentials(CertificateRequest certificateRequest) + throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsClientContextImpl.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsClientContextImpl.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsClientContextImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsClientContextImpl.java 2016-10-04 08:37:36.000000000 +0000 @@ -0,0 +1,18 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsCrypto; + +class TlsClientContextImpl + extends AbstractTlsContext + implements TlsClientContext +{ + TlsClientContextImpl(TlsCrypto crypto, SecurityParameters securityParameters) + { + super(crypto, securityParameters); + } + + public boolean isServer() + { + return false; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsClientContext.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsClientContext.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsClientContext.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsClientContext.java 2016-11-22 03:46:01.000000000 +0000 @@ -0,0 +1,9 @@ +package org.bouncycastle.tls; + +/** + * Marker interface to distinguish a TLS client context. + */ +public interface TlsClientContext + extends TlsContext +{ +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsClient.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsClient.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsClient.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsClient.java 2016-11-22 03:46:01.000000000 +0000 @@ -0,0 +1,98 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; + +/** + * Interface describing a TLS client endpoint. + */ +public interface TlsClient + extends TlsPeer +{ + void init(TlsClientContext context); + + /** + * Return the session this client wants to resume, if any. Note that the peer's certificate + * chain for the session (if any) may need to be periodically revalidated. + * + * @return A {@link TlsSession} representing the resumable session to be used for this + * connection, or null to use a new session. + * @see SessionParameters#getPeerCertificate() + */ + TlsSession getSessionToResume(); + + /** + * Return the {@link ProtocolVersion} to use for the TLSPlaintext.version field prior to + * receiving the server version. NOTE: This method is not called for DTLS. + * + *

      + * See RFC 5246 E.1.: "TLS clients that wish to negotiate with older servers MAY send any value + * {03,XX} as the record layer version number. Typical values would be {03,00}, the lowest + * version number supported by the client, and the value of ClientHello.client_version. No + * single value will guarantee interoperability with all old servers, but this is a complex + * topic beyond the scope of this document." + *

      + * + * @return The {@link ProtocolVersion} to use. + */ + ProtocolVersion getClientHelloRecordLayerVersion(); + + ProtocolVersion getClientVersion(); + + boolean isFallback(); + + int[] getCipherSuites(); + + short[] getCompressionMethods(); + + // Hashtable is (Integer -> byte[]) + Hashtable getClientExtensions() + throws IOException; + + void notifyServerVersion(ProtocolVersion selectedVersion) + throws IOException; + + /** + * Notifies the client of the session_id sent in the ServerHello. + * + * @param sessionID + * @see TlsContext#getSession() + */ + void notifySessionID(byte[] sessionID); + + void notifySelectedCipherSuite(int selectedCipherSuite); + + void notifySelectedCompressionMethod(short selectedCompressionMethod); + + // Hashtable is (Integer -> byte[]) + void processServerExtensions(Hashtable serverExtensions) + throws IOException; + + // Vector is (SupplementalDataEntry) + void processServerSupplementalData(Vector serverSupplementalData) + throws IOException; + + TlsKeyExchange getKeyExchange() + throws IOException; + + TlsAuthentication getAuthentication() + throws IOException; + + // Vector is (SupplementalDataEntry) + Vector getClientSupplementalData() + throws IOException; + + /** + * RFC 5077 3.3. NewSessionTicket Handshake Message + *

      + * This method will be called (only) when a NewSessionTicket handshake message is received. The + * ticket is opaque to the client and clients MUST NOT examine the ticket under the assumption + * that it complies with e.g. RFC 5077 4. Recommended Ticket Construction. + * + * @param newSessionTicket The ticket. + * @throws IOException + */ + void notifyNewSessionTicket(NewSessionTicket newSessionTicket) + throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java 2016-11-21 00:44:31.000000000 +0000 @@ -0,0 +1,937 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.util.Arrays; + +public class TlsClientProtocol + extends TlsProtocol +{ + protected TlsClient tlsClient = null; + TlsClientContextImpl tlsClientContext = null; + + protected byte[] selectedSessionID = null; + + protected TlsKeyExchange keyExchange = null; + protected TlsAuthentication authentication = null; + + protected CertificateStatus certificateStatus = null; + protected CertificateRequest certificateRequest = null; + + /** + * Constructor for non-blocking mode.
      + *
      + * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to + * provide the received ciphertext, then use + * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.
      + *
      + * Similarly, when data needs to be sent, use + * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use + * {@link #readOutput(byte[], int, int)} to get the corresponding + * ciphertext. + */ + public TlsClientProtocol() + { + super(); + } + + /** + * Constructor for blocking mode. + * @param input The stream of data from the server + * @param output The stream of data to the server + */ + public TlsClientProtocol(InputStream input, OutputStream output) + { + super(input, output); + } + + /** + * Initiates a TLS handshake in the role of client.
      + *
      + * In blocking mode, this will not return until the handshake is complete. + * In non-blocking mode, use {@link TlsPeer#notifyHandshakeComplete()} to + * receive a callback when the handshake is complete. + * + * @param tlsClient The {@link TlsClient} to use for the handshake. + * @throws IOException If in blocking mode and handshake was not successful. + */ + public void connect(TlsClient tlsClient) throws IOException + { + if (tlsClient == null) + { + throw new IllegalArgumentException("'tlsClient' cannot be null"); + } + if (this.tlsClient != null) + { + throw new IllegalStateException("'connect' can only be called once"); + } + + this.tlsClient = tlsClient; + + this.securityParameters = new SecurityParameters(); + this.securityParameters.entity = ConnectionEnd.client; + + this.tlsClientContext = new TlsClientContextImpl(tlsClient.getCrypto(), securityParameters); + + this.securityParameters.clientRandom = createRandomBlock(tlsClient.shouldUseGMTUnixTime(), tlsClientContext); + + this.tlsClient.init(tlsClientContext); + this.recordStream.init(tlsClientContext); + + TlsSession sessionToResume = tlsClient.getSessionToResume(); + if (sessionToResume != null && sessionToResume.isResumable()) + { + SessionParameters sessionParameters = sessionToResume.exportSessionParameters(); + if (sessionParameters != null) + { + this.tlsSession = sessionToResume; + this.sessionParameters = sessionParameters; + } + } + + sendClientHelloMessage(); + this.connection_state = CS_CLIENT_HELLO; + + blockForHandshake(); + } + + protected void cleanupHandshake() + { + super.cleanupHandshake(); + + this.selectedSessionID = null; + this.keyExchange = null; + this.authentication = null; + this.certificateStatus = null; + this.certificateRequest = null; + } + + protected TlsContext getContext() + { + return tlsClientContext; + } + + AbstractTlsContext getContextAdmin() + { + return tlsClientContext; + } + + protected TlsPeer getPeer() + { + return tlsClient; + } + + protected void handleHandshakeMessage(short type, byte[] data) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(data); + + if (this.resumedSession) + { + if (type != HandshakeType.finished || this.connection_state != CS_SERVER_HELLO) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + processFinishedMessage(buf); + this.connection_state = CS_SERVER_FINISHED; + + sendFinishedMessage(); + this.connection_state = CS_CLIENT_FINISHED; + this.connection_state = CS_END; + + completeHandshake(); + return; + } + + switch (type) + { + case HandshakeType.certificate: + { + switch (this.connection_state) + { + case CS_SERVER_HELLO: + { + handleSupplementalData(null); + // NB: Fall through to next case label + } + case CS_SERVER_SUPPLEMENTAL_DATA: + { + // Parse the Certificate message and send to cipher suite + + this.peerCertificate = Certificate.parse(getContext(), buf); + + assertEmpty(buf); + + // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus + if (this.peerCertificate == null || this.peerCertificate.isEmpty()) + { + this.allowCertificateStatus = false; + } + + this.keyExchange.processServerCertificate(this.peerCertificate); + + this.authentication = tlsClient.getAuthentication(); + this.authentication.notifyServerCertificate(this.peerCertificate); + + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + this.connection_state = CS_SERVER_CERTIFICATE; + break; + } + case HandshakeType.certificate_status: + { + switch (this.connection_state) + { + case CS_SERVER_CERTIFICATE: + { + if (!this.allowCertificateStatus) + { + /* + * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the + * server MUST have included an extension of type "status_request" with empty + * "extension_data" in the extended server hello.. + */ + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + this.certificateStatus = CertificateStatus.parse(buf); + + assertEmpty(buf); + + // TODO[RFC 3546] Figure out how to provide this to the client/authentication. + + this.connection_state = CS_CERTIFICATE_STATUS; + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + break; + } + case HandshakeType.finished: + { + switch (this.connection_state) + { + case CS_CLIENT_FINISHED: + { + if (this.expectSessionTicket) + { + /* + * RFC 5077 3.3. This message MUST be sent if the server included a + * SessionTicket extension in the ServerHello. + */ + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + // NB: Fall through to next case label + } + case CS_SERVER_SESSION_TICKET: + { + processFinishedMessage(buf); + this.connection_state = CS_SERVER_FINISHED; + this.connection_state = CS_END; + + completeHandshake(); + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + break; + } + case HandshakeType.server_hello: + { + switch (this.connection_state) + { + case CS_CLIENT_HELLO: + { + receiveServerHelloMessage(buf); + this.connection_state = CS_SERVER_HELLO; + + this.recordStream.notifyHelloComplete(); + + applyMaxFragmentLengthExtension(); + + if (this.resumedSession) + { + this.securityParameters.masterSecret = getContext().getCrypto().adoptSecret(sessionParameters.getMasterSecret()); + this.recordStream.setPendingConnectionState(getPeer().getCompression(), getPeer().getCipher()); + + sendChangeCipherSpecMessage(); + } + else + { + invalidateSession(); + + this.tlsSession = TlsUtils.importSession(this.selectedSessionID, null); + this.sessionParameters = null; + } + + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + break; + } + case HandshakeType.supplemental_data: + { + switch (this.connection_state) + { + case CS_SERVER_HELLO: + { + handleSupplementalData(readSupplementalDataMessage(buf)); + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + break; + } + case HandshakeType.server_hello_done: + { + switch (this.connection_state) + { + case CS_SERVER_HELLO: + { + handleSupplementalData(null); + // NB: Fall through to next case label + } + case CS_SERVER_SUPPLEMENTAL_DATA: + { + // There was no server certificate message; check it's OK + this.keyExchange.skipServerCredentials(); + this.authentication = null; + + // NB: Fall through to next case label + } + case CS_SERVER_CERTIFICATE: + case CS_CERTIFICATE_STATUS: + { + // There was no server key exchange message; check it's OK + this.keyExchange.skipServerKeyExchange(); + + // NB: Fall through to next case label + } + case CS_SERVER_KEY_EXCHANGE: + case CS_CERTIFICATE_REQUEST: + { + assertEmpty(buf); + + this.connection_state = CS_SERVER_HELLO_DONE; + + this.recordStream.getHandshakeHash().sealHashAlgorithms(); + + Vector clientSupplementalData = tlsClient.getClientSupplementalData(); + if (clientSupplementalData != null) + { + sendSupplementalDataMessage(clientSupplementalData); + } + this.connection_state = CS_CLIENT_SUPPLEMENTAL_DATA; + + TlsCredentials clientCreds = null; + if (certificateRequest == null) + { + this.keyExchange.skipClientCredentials(); + } + else + { + clientCreds = validateCredentials(this.authentication.getClientCredentials(certificateRequest)); + + if (clientCreds == null) + { + this.keyExchange.skipClientCredentials(); + + /* + * RFC 5246 If no suitable certificate is available, the client MUST send a + * certificate message containing no certificates. + * + * NOTE: In previous RFCs, this was SHOULD instead of MUST. + */ + sendCertificateMessage(Certificate.EMPTY_CHAIN); + } + else + { + this.keyExchange.processClientCredentials(clientCreds); + + sendCertificateMessage(clientCreds.getCertificate()); + } + } + + this.connection_state = CS_CLIENT_CERTIFICATE; + + /* + * Send the client key exchange message, depending on the key exchange we are using + * in our CipherSuite. + */ + sendClientKeyExchangeMessage(); + this.connection_state = CS_CLIENT_KEY_EXCHANGE; + + if (TlsUtils.isSSL(getContext())) + { + establishMasterSecret(getContext(), keyExchange); + } + + TlsHandshakeHash prepareFinishHash = recordStream.prepareToFinish(); + this.securityParameters.sessionHash = getCurrentPRFHash(getContext(), prepareFinishHash, null); + + if (!TlsUtils.isSSL(getContext())) + { + establishMasterSecret(getContext(), keyExchange); + } + + recordStream.setPendingConnectionState(getPeer().getCompression(), getPeer().getCipher()); + + if (clientCreds != null && clientCreds instanceof TlsCredentialedSigner) + { + TlsCredentialedSigner signerCredentials = (TlsCredentialedSigner)clientCreds; + + /* + * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 + */ + SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtils.getSignatureAndHashAlgorithm( + getContext(), signerCredentials); + + byte[] hash; + if (signatureAndHashAlgorithm == null) + { + hash = securityParameters.getSessionHash(); + } + else + { + hash = prepareFinishHash.getFinalHash(signatureAndHashAlgorithm.getHash()); + } + + byte[] signature = signerCredentials.generateRawSignature(hash); + DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature); + sendCertificateVerifyMessage(certificateVerify); + + this.connection_state = CS_CERTIFICATE_VERIFY; + } + + sendChangeCipherSpecMessage(); + sendFinishedMessage(); + break; + } + default: + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + this.connection_state = CS_CLIENT_FINISHED; + break; + } + case HandshakeType.server_key_exchange: + { + switch (this.connection_state) + { + case CS_SERVER_HELLO: + { + handleSupplementalData(null); + // NB: Fall through to next case label + } + case CS_SERVER_SUPPLEMENTAL_DATA: + { + // There was no server certificate message; check it's OK + this.keyExchange.skipServerCredentials(); + this.authentication = null; + + // NB: Fall through to next case label + } + case CS_SERVER_CERTIFICATE: + case CS_CERTIFICATE_STATUS: + { + this.keyExchange.processServerKeyExchange(buf); + + assertEmpty(buf); + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + this.connection_state = CS_SERVER_KEY_EXCHANGE; + break; + } + case HandshakeType.certificate_request: + { + switch (this.connection_state) + { + case CS_SERVER_CERTIFICATE: + case CS_CERTIFICATE_STATUS: + { + // There was no server key exchange message; check it's OK + this.keyExchange.skipServerKeyExchange(); + + // NB: Fall through to next case label + } + case CS_SERVER_KEY_EXCHANGE: + { + if (this.authentication == null) + { + /* + * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server + * to request client identification. + */ + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + this.certificateRequest = CertificateRequest.parse(getContext(), buf); + + assertEmpty(buf); + + this.keyExchange.validateCertificateRequest(this.certificateRequest); + + /* + * TODO Give the client a chance to immediately select the CertificateVerify hash + * algorithm here to avoid tracking the other hash algorithms unnecessarily? + */ + TlsUtils.trackHashAlgorithms(this.recordStream.getHandshakeHash(), + this.certificateRequest.getSupportedSignatureAlgorithms()); + + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + this.connection_state = CS_CERTIFICATE_REQUEST; + break; + } + case HandshakeType.session_ticket: + { + switch (this.connection_state) + { + case CS_CLIENT_FINISHED: + { + if (!this.expectSessionTicket) + { + /* + * RFC 5077 3.3. This message MUST NOT be sent if the server did not include a + * SessionTicket extension in the ServerHello. + */ + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + /* + * RFC 5077 3.4. If the client receives a session ticket from the server, then it + * discards any Session ID that was sent in the ServerHello. + */ + invalidateSession(); + + receiveNewSessionTicketMessage(buf); + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + this.connection_state = CS_SERVER_SESSION_TICKET; + break; + } + case HandshakeType.hello_request: + { + assertEmpty(buf); + + /* + * RFC 2246 7.4.1.1 Hello request This message will be ignored by the client if the + * client is currently negotiating a session. This message may be ignored by the client + * if it does not wish to renegotiate a session, or the client may, if it wishes, + * respond with a no_renegotiation alert. + */ + if (this.connection_state == CS_END) + { + refuseRenegotiation(); + } + break; + } + case HandshakeType.client_hello: + case HandshakeType.client_key_exchange: + case HandshakeType.certificate_verify: + case HandshakeType.hello_verify_request: + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + } + + protected void handleSupplementalData(Vector serverSupplementalData) + throws IOException + { + this.tlsClient.processServerSupplementalData(serverSupplementalData); + this.connection_state = CS_SERVER_SUPPLEMENTAL_DATA; + + this.keyExchange = tlsClient.getKeyExchange(); + this.keyExchange.init(getContext()); + } + + protected void receiveNewSessionTicketMessage(ByteArrayInputStream buf) + throws IOException + { + NewSessionTicket newSessionTicket = NewSessionTicket.parse(buf); + + assertEmpty(buf); + + tlsClient.notifyNewSessionTicket(newSessionTicket); + } + + protected void receiveServerHelloMessage(ByteArrayInputStream buf) + throws IOException + { + { + ProtocolVersion server_version = TlsUtils.readVersion(buf); + if (server_version.isDTLS()) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + // Check that this matches what the server is sending in the record layer + if (!server_version.equals(this.recordStream.getReadVersion())) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + ProtocolVersion client_version = getContext().getClientVersion(); + if (!server_version.isEqualOrEarlierVersionOf(client_version)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + this.recordStream.setWriteVersion(server_version); + getContextAdmin().setServerVersion(server_version); + this.tlsClient.notifyServerVersion(server_version); + } + + /* + * Read the server random + */ + this.securityParameters.serverRandom = TlsUtils.readFully(32, buf); + + this.selectedSessionID = TlsUtils.readOpaque8(buf); + if (this.selectedSessionID.length > 32) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + this.tlsClient.notifySessionID(this.selectedSessionID); + this.resumedSession = this.selectedSessionID.length > 0 && this.tlsSession != null + && Arrays.areEqual(this.selectedSessionID, this.tlsSession.getSessionID()); + + /* + * Find out which CipherSuite the server has chosen and check that it was one of the offered + * ones, and is a valid selection for the negotiated version. + */ + int selectedCipherSuite = TlsUtils.readUint16(buf); + if (!Arrays.contains(this.offeredCipherSuites, selectedCipherSuite) + || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL + || CipherSuite.isSCSV(selectedCipherSuite) + || !TlsUtils.isValidCipherSuiteForVersion(selectedCipherSuite, getContext().getServerVersion())) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + this.tlsClient.notifySelectedCipherSuite(selectedCipherSuite); + + /* + * Find out which CompressionMethod the server has chosen and check that it was one of the + * offered ones. + */ + short selectedCompressionMethod = TlsUtils.readUint8(buf); + if (!Arrays.contains(this.offeredCompressionMethods, selectedCompressionMethod)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + this.tlsClient.notifySelectedCompressionMethod(selectedCompressionMethod); + + /* + * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server + * hello message when the client has requested extended functionality via the extended + * client hello message specified in Section 2.1. ... Note that the extended server hello + * message is only sent in response to an extended client hello message. This prevents the + * possibility that the extended server hello message could "break" existing TLS 1.0 + * clients. + */ + this.serverExtensions = readExtensions(buf); + + /* + * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an + * extended client hello message. + * + * However, see RFC 5746 exception below. We always include the SCSV, so an Extended Server + * Hello is always allowed. + */ + if (this.serverExtensions != null) + { + Enumeration e = this.serverExtensions.keys(); + while (e.hasMoreElements()) + { + Integer extType = (Integer)e.nextElement(); + + /* + * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a + * ClientHello containing only the SCSV is an explicit exception to the prohibition + * in RFC 5246, Section 7.4.1.4, on the server sending unsolicited extensions and is + * only allowed because the client is signaling its willingness to receive the + * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. + */ + if (extType.equals(EXT_RenegotiationInfo)) + { + continue; + } + + /* + * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the + * same extension type appeared in the corresponding ClientHello. If a client + * receives an extension type in ServerHello that it did not request in the + * associated ClientHello, it MUST abort the handshake with an unsupported_extension + * fatal alert. + */ + if (null == TlsUtils.getExtensionData(this.clientExtensions, extType)) + { + throw new TlsFatalAlert(AlertDescription.unsupported_extension); + } + + /* + * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore + * extensions appearing in the client hello, and send a server hello containing no + * extensions[.] + */ + if (this.resumedSession) + { + // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats + // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats + // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats +// throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + /* + * RFC 5746 3.4. Client Behavior: Initial Handshake + */ + { + /* + * When a ServerHello is received, the client MUST check if it includes the + * "renegotiation_info" extension: + */ + byte[] renegExtData = TlsUtils.getExtensionData(this.serverExtensions, EXT_RenegotiationInfo); + if (renegExtData != null) + { + /* + * If the extension is present, set the secure_renegotiation flag to TRUE. The + * client MUST then verify that the length of the "renegotiated_connection" + * field is zero, and if it is not, MUST abort the handshake (by sending a fatal + * handshake_failure alert). + */ + this.secure_renegotiation = true; + + if (!Arrays.constantTimeAreEqual(renegExtData, createRenegotiationInfo(TlsUtils.EMPTY_BYTES))) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + } + } + + // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming + this.tlsClient.notifySecureRenegotiation(this.secure_renegotiation); + + Hashtable sessionClientExtensions = clientExtensions, sessionServerExtensions = serverExtensions; + if (this.resumedSession) + { + if (selectedCipherSuite != this.sessionParameters.getCipherSuite() + || selectedCompressionMethod != this.sessionParameters.getCompressionAlgorithm()) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + sessionClientExtensions = null; + sessionServerExtensions = this.sessionParameters.readServerExtensions(); + } + + this.securityParameters.cipherSuite = selectedCipherSuite; + this.securityParameters.compressionAlgorithm = selectedCompressionMethod; + + if (sessionServerExtensions != null) + { + { + /* + * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client + * and then selects a stream or Authenticated Encryption with Associated Data (AEAD) + * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the + * client. + */ + boolean serverSentEncryptThenMAC = TlsExtensionsUtils.hasEncryptThenMACExtension(sessionServerExtensions); + if (serverSentEncryptThenMAC && !TlsUtils.isBlockCipherSuite(selectedCipherSuite)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + this.securityParameters.encryptThenMAC = serverSentEncryptThenMAC; + } + + this.securityParameters.extendedMasterSecret = TlsExtensionsUtils.hasExtendedMasterSecretExtension(sessionServerExtensions); + + this.securityParameters.maxFragmentLength = processMaxFragmentLengthExtension(sessionClientExtensions, + sessionServerExtensions, AlertDescription.illegal_parameter); + + this.securityParameters.truncatedHMac = TlsExtensionsUtils.hasTruncatedHMacExtension(sessionServerExtensions); + + /* + * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in + * a session resumption handshake. + */ + this.allowCertificateStatus = !this.resumedSession + && TlsUtils.hasExpectedEmptyExtensionData(sessionServerExtensions, + TlsExtensionsUtils.EXT_status_request, AlertDescription.illegal_parameter); + + this.expectSessionTicket = !this.resumedSession + && TlsUtils.hasExpectedEmptyExtensionData(sessionServerExtensions, TlsProtocol.EXT_SessionTicket, + AlertDescription.illegal_parameter); + } + + /* + * TODO[session-hash] + * + * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes + * that do not use the extended master secret [..]. (and see 5.2, 5.3) + */ + + if (sessionClientExtensions != null) + { + this.tlsClient.processServerExtensions(sessionServerExtensions); + } + + this.securityParameters.prfAlgorithm = getPRFAlgorithm(getContext(), + this.securityParameters.getCipherSuite()); + + /* + * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify + * verify_data_length has a verify_data_length equal to 12. This includes all + * existing cipher suites. + */ + this.securityParameters.verifyDataLength = 12; + } + + protected void sendCertificateVerifyMessage(DigitallySigned certificateVerify) + throws IOException + { + HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_verify); + + certificateVerify.encode(message); + + message.writeToRecordStream(); + } + + protected void sendClientHelloMessage() + throws IOException + { + this.recordStream.setWriteVersion(this.tlsClient.getClientHelloRecordLayerVersion()); + + ProtocolVersion client_version = this.tlsClient.getClientVersion(); + if (client_version.isDTLS()) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + getContextAdmin().setClientVersion(client_version); + + /* + * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a + * Session ID in the TLS ClientHello. + */ + byte[] session_id = TlsUtils.EMPTY_BYTES; + if (this.tlsSession != null) + { + session_id = this.tlsSession.getSessionID(); + if (session_id == null || session_id.length > 32) + { + session_id = TlsUtils.EMPTY_BYTES; + } + } + + boolean fallback = this.tlsClient.isFallback(); + + this.offeredCipherSuites = this.tlsClient.getCipherSuites(); + + this.offeredCompressionMethods = this.tlsClient.getCompressionMethods(); + + if (session_id.length > 0 && this.sessionParameters != null) + { + if (!Arrays.contains(this.offeredCipherSuites, sessionParameters.getCipherSuite()) + || !Arrays.contains(this.offeredCompressionMethods, sessionParameters.getCompressionAlgorithm())) + { + session_id = TlsUtils.EMPTY_BYTES; + } + } + + this.clientExtensions = this.tlsClient.getClientExtensions(); + + HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello); + + TlsUtils.writeVersion(client_version, message); + + message.write(this.securityParameters.getClientRandom()); + + TlsUtils.writeOpaque8(session_id, message); + + // Cipher Suites (and SCSV) + { + /* + * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension, + * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the + * ClientHello. Including both is NOT RECOMMENDED. + */ + byte[] renegExtData = TlsUtils.getExtensionData(clientExtensions, EXT_RenegotiationInfo); + boolean noRenegExt = (null == renegExtData); + + boolean noRenegSCSV = !Arrays.contains(offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + + if (noRenegExt && noRenegSCSV) + { + // TODO Consider whether to default to a client extension instead +// this.clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(this.clientExtensions); +// this.clientExtensions.put(EXT_RenegotiationInfo, createRenegotiationInfo(TlsUtils.EMPTY_BYTES)); + this.offeredCipherSuites = Arrays.append(offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + } + + /* + * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value + * than the latest (highest-valued) version supported by the client, it SHOULD include + * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The + * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends + * to negotiate.) + */ + if (fallback && !Arrays.contains(offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)) + { + this.offeredCipherSuites = Arrays.append(offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV); + } + + TlsUtils.writeUint16ArrayWithUint16Length(offeredCipherSuites, message); + } + + TlsUtils.writeUint8ArrayWithUint8Length(offeredCompressionMethods, message); + + if (clientExtensions != null) + { + writeExtensions(message, clientExtensions); + } + + message.writeToRecordStream(); + } + + protected void sendClientKeyExchangeMessage() + throws IOException + { + HandshakeMessage message = new HandshakeMessage(HandshakeType.client_key_exchange); + + this.keyExchange.generateClientKeyExchange(message); + + message.writeToRecordStream(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsCompression.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsCompression.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsCompression.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsCompression.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,10 @@ +package org.bouncycastle.tls; + +import java.io.OutputStream; + +public interface TlsCompression +{ + OutputStream compress(OutputStream output); + + OutputStream decompress(OutputStream output); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsContext.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsContext.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsContext.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsContext.java 2016-11-28 09:01:16.000000000 +0000 @@ -0,0 +1,51 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsCrypto; + +public interface TlsContext +{ + TlsCrypto getCrypto(); + + SecurityParameters getSecurityParameters(); + + boolean isServer(); + + ProtocolVersion getClientVersion(); + + ProtocolVersion getServerVersion(); + + /** + * Used to get the resumable session, if any, used by this connection. Only available after the + * handshake has successfully completed. + * + * @return A {@link TlsSession} representing the resumable session used by this connection, or + * null if no resumable session available. + * @see TlsPeer#notifyHandshakeComplete() + */ + TlsSession getResumableSession(); + + /** + * Used to get the session information for this connection. Only available after the handshake + * has successfully completed. Use {@link TlsSession#isResumable()} to find out if the session + * is resumable. + * + * @return A {@link TlsSession} representing the session used by this connection. + * @see TlsPeer#notifyHandshakeComplete() + */ + TlsSession getSession(); + + Object getUserObject(); + + void setUserObject(Object userObject); + + /** + * Export keying material according to RFC 5705: "Keying Material Exporters for TLS". + * + * @param asciiLabel indicates which application will use the exported keys. + * @param context_value allows the application using the exporter to mix its own data with the TLS PRF for + * the exporter output. + * @param length the number of bytes to generate + * @return a pseudorandom bit string of 'length' bytes generated from the master_secret. + */ + byte[] exportKeyingMaterial(String asciiLabel, byte[] context_value, int length); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedAgreement.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedAgreement.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedAgreement.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedAgreement.java 2016-10-09 23:42:26.000000000 +0000 @@ -0,0 +1,22 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsSecret; + +/** + * Support interface for generating a secret based on the credentials sent by a TLS peer. + */ +public interface TlsCredentialedAgreement + extends TlsCredentials +{ + /** + * Calculate an agreed secret based on our credentials and the public key credentials of our peer. + * + * @param peerCertificate public key certificate of our TLS peer. + * @return the agreed secret. + * @throws IOException in case of an exception on generation of the secret. + */ + TlsSecret generateAgreement(TlsCertificate peerCertificate) throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedDecryptor.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedDecryptor.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedDecryptor.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedDecryptor.java 2016-10-05 02:57:13.000000000 +0000 @@ -0,0 +1,12 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsSecret; + +public interface TlsCredentialedDecryptor + extends TlsCredentials +{ + TlsSecret decrypt(TlsCryptoParameters cryptoParams, byte[] ciphertext) throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedSigner.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedSigner.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedSigner.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsCredentialedSigner.java 2016-10-09 23:42:26.000000000 +0000 @@ -0,0 +1,27 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +/** + * Support interface for generating a signature based on our private credentials. + */ +public interface TlsCredentialedSigner + extends TlsCredentials +{ + /** + * Generate a signature against the passed in hash. + * + * @param hash a message digest calculated across the message the signature is to apply to. + * @return an encoded signature. + * @throws IOException if the hash cannot be processed, or there is an issue with the private credentials. + */ + byte[] generateRawSignature(byte[] hash) + throws IOException; + + /** + * Return the algorithm IDs for the signature algorithm and the associated hash it uses. + * + * @return the full algorithm details for the signature. + */ + SignatureAndHashAlgorithm getSignatureAndHashAlgorithm(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsCredentials.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsCredentials.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsCredentials.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsCredentials.java 2016-10-01 21:03:28.000000000 +0000 @@ -0,0 +1,14 @@ +package org.bouncycastle.tls; + +/** + * Base interface for interfaces/classes carrying TLS credentials. + */ +public interface TlsCredentials +{ + /** + * Return the certificate structure representing our identity. + * + * @return our certificate structure. + */ + Certificate getCertificate(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsDHConfigVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsDHConfigVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsDHConfigVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsDHConfigVerifier.java 2016-06-21 08:07:50.000000000 +0000 @@ -0,0 +1,14 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsDHConfig; + +public interface TlsDHConfigVerifier +{ + /** + * Check whether the given DH configuration is acceptable for use. + * + * @param dhConfig the {@link TlsDHConfig} to check + * @return true if (and only if) the specified configuration is acceptable + */ + boolean accept(TlsDHConfig dhConfig); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsDHEKeyExchange.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsDHEKeyExchange.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsDHEKeyExchange.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsDHEKeyExchange.java 2016-10-05 02:02:28.000000000 +0000 @@ -0,0 +1,130 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsVerifier; +import org.bouncycastle.util.io.TeeInputStream; + +public class TlsDHEKeyExchange + extends TlsDHKeyExchange +{ + private static int checkKeyExchange(int keyExchange) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_RSA: + return keyExchange; + default: + throw new IllegalArgumentException("unsupported key exchange algorithm"); + } + } + + protected TlsCredentialedSigner serverCredentials = null; + protected TlsVerifier verifier = null; + + public TlsDHEKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsDHConfigVerifier dhConfigVerifier) + { + super(checkKeyExchange(keyExchange), supportedSignatureAlgorithms, dhConfigVerifier); + } + + public TlsDHEKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsDHConfig dhConfig) + { + super(checkKeyExchange(keyExchange), supportedSignatureAlgorithms, dhConfig); + } + + public void processServerCredentials(TlsCredentials serverCredentials) throws IOException + { + if (!(serverCredentials instanceof TlsCredentialedSigner)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.serverCredentials = (TlsCredentialedSigner)serverCredentials; + } + + public void processServerCertificate(Certificate serverCertificate) throws IOException + { + if (serverCertificate.isEmpty()) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + checkServerCertSigAlg(serverCertificate); + + this.verifier = serverCertificate.getCertificateAt(0) + .createVerifier(TlsUtils.getSignatureAlgorithm(keyExchange)); + } + + public byte[] generateServerKeyExchange() throws IOException + { + if (this.dhConfig == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + DigestInputBuffer buf = new DigestInputBuffer(); + + TlsDHUtils.writeDHConfig(dhConfig, buf); + + this.agreement = context.getCrypto().createDHDomain(dhConfig).createDH(); + + generateEphemeral(buf); + + DigitallySigned signedParams = TlsUtils.generateServerKeyExchangeSignature(context, serverCredentials, buf); + + signedParams.encode(buf); + + return buf.toByteArray(); + } + + public void processServerKeyExchange(InputStream input) throws IOException + { + DigestInputBuffer buf = new DigestInputBuffer(); + InputStream teeIn = new TeeInputStream(input, buf); + + this.dhConfig = TlsDHUtils.receiveDHConfig(dhConfigVerifier, teeIn); + + byte[] y = TlsUtils.readOpaque16(teeIn); + + DigitallySigned signedParams = parseSignature(input); + + TlsUtils.verifyServerKeyExchangeSignature(context, verifier, buf, signedParams); + + this.agreement = context.getCrypto().createDHDomain(dhConfig).createDH(); + + processEphemeral(y); + } + + public void validateCertificateRequest(CertificateRequest certificateRequest) throws IOException + { + short[] types = certificateRequest.getCertificateTypes(); + for (int i = 0; i < types.length; ++i) + { + switch (types[i]) + { + case ClientCertificateType.dss_sign: + case ClientCertificateType.ecdsa_sign: + case ClientCertificateType.rsa_sign: + break; + default: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + public void processClientCredentials(TlsCredentials clientCredentials) throws IOException + { + if (clientCredentials instanceof TlsCredentialedSigner) + { + // OK + } + else + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsDHKeyExchange.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsDHKeyExchange.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsDHKeyExchange.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsDHKeyExchange.java 2016-11-01 20:33:01.000000000 +0000 @@ -0,0 +1,262 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsSecret; + +/** + * (D)TLS DH key exchange. + */ +public class TlsDHKeyExchange + extends AbstractTlsKeyExchange +{ + private static int checkKeyExchange(int keyExchange) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.DH_anon: + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DH_RSA: + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_RSA: + return keyExchange; + default: + throw new IllegalArgumentException("unsupported key exchange algorithm"); + } + } + + protected TlsDHConfigVerifier dhConfigVerifier; + + protected TlsCredentialedAgreement agreementCredentials; + protected TlsCertificate dhPeerCertificate; + + protected TlsDHConfig dhConfig; + protected TlsAgreement agreement; + + public TlsDHKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsDHConfigVerifier dhConfigVerifier) + { + this(keyExchange, supportedSignatureAlgorithms, dhConfigVerifier, null); + } + + public TlsDHKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsDHConfig dhConfig) + { + this(keyExchange, supportedSignatureAlgorithms, null, dhConfig); + } + + private TlsDHKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsDHConfigVerifier dhConfigVerifier, + TlsDHConfig dhConfig) + { + super(checkKeyExchange(keyExchange), supportedSignatureAlgorithms); + + this.dhConfigVerifier = dhConfigVerifier; + this.dhConfig = dhConfig; + } + + public void skipServerCredentials() throws IOException + { + if (keyExchange != KeyExchangeAlgorithm.DH_anon) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public void processServerCredentials(TlsCredentials serverCredentials) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.DH_anon) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + if (!(serverCredentials instanceof TlsCredentialedAgreement)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.agreementCredentials = (TlsCredentialedAgreement)serverCredentials; + } + + public void processServerCertificate(Certificate serverCertificate) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.DH_anon) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + checkServerCertSigAlg(serverCertificate); + + this.dhPeerCertificate = validatePeerCertificate(ConnectionEnd.server, serverCertificate); + } + + public boolean requiresServerKeyExchange() + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.DH_anon: + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_RSA: + return true; + default: + return false; + } + } + + public byte[] generateServerKeyExchange() throws IOException + { + if (!requiresServerKeyExchange()) + { + return null; + } + + // DH_anon is handled here, DHE_* in a subclass + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + TlsDHUtils.writeDHConfig(dhConfig, buf); + + this.agreement = context.getCrypto().createDHDomain(dhConfig).createDH(); + + generateEphemeral(buf); + + return buf.toByteArray(); + } + + public void processServerKeyExchange(InputStream input) throws IOException + { + if (!requiresServerKeyExchange()) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + // DH_anon is handled here, DHE_* in a subclass + + this.dhConfig = TlsDHUtils.receiveDHConfig(dhConfigVerifier, input); + + byte[] y = TlsUtils.readOpaque16(input); + + this.agreement = context.getCrypto().createDHDomain(dhConfig).createDH(); + + processEphemeral(y); + } + + public void validateCertificateRequest(CertificateRequest certificateRequest) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.DH_anon) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + short[] types = certificateRequest.getCertificateTypes(); + for (int i = 0; i < types.length; ++i) + { + switch (types[i]) + { + case ClientCertificateType.dss_fixed_dh: + case ClientCertificateType.rsa_fixed_dh: + break; + default: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + public void processClientCredentials(TlsCredentials clientCredentials) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.DH_anon) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + if (clientCredentials instanceof TlsCredentialedAgreement) + { + this.agreementCredentials = (TlsCredentialedAgreement)clientCredentials; + + // TODO Check that the client certificate's domain parameters match the server's? + } + else + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public void generateClientKeyExchange(OutputStream output) throws IOException + { + /* + * RFC 2246 7.4.7.2 If the client certificate already contains a suitable Diffie-Hellman + * key, then Yc is implicit and does not need to be sent again. In this case, the Client Key + * Exchange message will be sent, but will be empty. + */ + if (agreementCredentials == null) + { + generateEphemeral(output); + } + } + + public void processClientCertificate(Certificate clientCertificate) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.DH_anon) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + if (agreementCredentials != null) + { + // TODO[tls-ops] Where to check that the domain parameters match the server's? + this.dhPeerCertificate = validatePeerCertificate(ConnectionEnd.client, clientCertificate); + } + } + + public void processClientKeyExchange(InputStream input) throws IOException + { + if (dhPeerCertificate != null) + { + // For dss_fixed_dh and rsa_fixed_dh, the key arrived in the client certificate + return; + } + + byte[] y = TlsUtils.readOpaque16(input); + + processEphemeral(y); + } + + public TlsSecret generatePreMasterSecret() throws IOException + { + if (agreementCredentials != null) + { + return agreementCredentials.generateAgreement(dhPeerCertificate); + } + + if (agreement != null) + { + return agreement.calculateSecret(); + } + + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected void generateEphemeral(OutputStream output) throws IOException + { + byte[] y = agreement.generateEphemeral(); + TlsUtils.writeOpaque16(y, output); + } + + protected void processEphemeral(byte[] y) throws IOException + { + this.agreement.receivePeerValue(y); + } + + protected TlsCertificate validatePeerCertificate(int connectionEnd, Certificate peerCertificate) throws IOException + { + if (peerCertificate.isEmpty()) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + return peerCertificate.getCertificateAt(0).useInRole(connectionEnd, keyExchange); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsDHUtils.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsDHUtils.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsDHUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsDHUtils.java 2016-10-03 01:49:36.000000000 +0000 @@ -0,0 +1,365 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.Hashtable; + +import org.bouncycastle.tls.crypto.DHGroup; +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.util.BigIntegers; +import org.bouncycastle.util.Integers; +import org.bouncycastle.util.encoders.Hex; + +public class TlsDHUtils +{ + static final BigInteger TWO = BigInteger.valueOf(2); + + public static final Integer EXT_negotiated_ff_dhe_groups = Integers.valueOf(ExtensionType.negotiated_ff_dhe_groups); + + /* + * TODO[draft-ietf-tls-negotiated-ff-dhe-01] Move these groups to DHStandardGroups once reaches RFC + */ + private static BigInteger fromHex(String hex) + { + return new BigInteger(1, Hex.decode(hex)); + } + + private static DHGroup fromSafeP(String hexP) + { + BigInteger p = fromHex(hexP), q = p.shiftRight(1); + return new DHGroup(p, q, TWO); + } + + private static final String draft_ffdhe2432_p = + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE13098533C8B3FFFFFFFFFFFFFFFF"; + static final DHGroup draft_ffdhe2432 = fromSafeP(draft_ffdhe2432_p); + + private static final String draft_ffdhe3072_p = + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF"; + static final DHGroup draft_ffdhe3072 = fromSafeP(draft_ffdhe3072_p); + + private static final String draft_ffdhe4096_p = + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A" + + "FFFFFFFFFFFFFFFF"; + static final DHGroup draft_ffdhe4096 = fromSafeP(draft_ffdhe4096_p); + + private static final String draft_ffdhe6144_p = + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + + "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + + "A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF"; + static final DHGroup draft_ffdhe6144 = fromSafeP(draft_ffdhe6144_p); + + private static final String draft_ffdhe8192_p = + "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + + "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + + "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + + "A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C838" + + "1E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E" + + "0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665" + + "CB2C0F1CC01BD70229388839D2AF05E454504AC78B758282" + + "2846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022" + + "BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C" + + "51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9" + + "D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA457" + + "1EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30" + + "FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D" + + "97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88C" + + "D68C8BB7C5C6424CFFFFFFFFFFFFFFFF"; + static final DHGroup draft_ffdhe8192 = fromSafeP(draft_ffdhe8192_p); + + + public static void addNegotiatedDHEGroupsClientExtension(Hashtable extensions, short[] dheGroups) + throws IOException + { + extensions.put(EXT_negotiated_ff_dhe_groups, createNegotiatedDHEGroupsClientExtension(dheGroups)); + } + + public static void addNegotiatedDHEGroupsServerExtension(Hashtable extensions, short dheGroup) + throws IOException + { + extensions.put(EXT_negotiated_ff_dhe_groups, createNegotiatedDHEGroupsServerExtension(dheGroup)); + } + + public static short[] getNegotiatedDHEGroupsClientExtension(Hashtable extensions) throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_negotiated_ff_dhe_groups); + return extensionData == null ? null : readNegotiatedDHEGroupsClientExtension(extensionData); + } + + public static short getNegotiatedDHEGroupsServerExtension(Hashtable extensions) throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_negotiated_ff_dhe_groups); + return extensionData == null ? -1 : readNegotiatedDHEGroupsServerExtension(extensionData); + } + + public static byte[] createNegotiatedDHEGroupsClientExtension(short[] dheGroups) throws IOException + { + if (dheGroups == null || dheGroups.length < 1 || dheGroups.length > 255) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + return TlsUtils.encodeUint8ArrayWithUint8Length(dheGroups); + } + + public static byte[] createNegotiatedDHEGroupsServerExtension(short dheGroup) throws IOException + { + TlsUtils.checkUint8(dheGroup); + + byte[] extensionData = new byte[1]; + TlsUtils.writeUint8(dheGroup, extensionData, 0); + return extensionData; + } + + public static short[] readNegotiatedDHEGroupsClientExtension(byte[] extensionData) throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(extensionData); + + short length = TlsUtils.readUint8(buf); + if (length < 1) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + short[] dheGroups = TlsUtils.readUint8Array(length, buf); + + TlsProtocol.assertEmpty(buf); + + return dheGroups; + } + + public static short readNegotiatedDHEGroupsServerExtension(byte[] extensionData) throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + if (extensionData.length != 1) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + return TlsUtils.readUint8(extensionData, 0); + } + + public static DHGroup getParametersForDHEGroup(short dheGroup) + { + switch (dheGroup) + { + case FiniteFieldDHEGroup.ffdhe2432: + return draft_ffdhe2432; + case FiniteFieldDHEGroup.ffdhe3072: + return draft_ffdhe3072; + case FiniteFieldDHEGroup.ffdhe4096: + return draft_ffdhe4096; + case FiniteFieldDHEGroup.ffdhe6144: + return draft_ffdhe6144; + case FiniteFieldDHEGroup.ffdhe8192: + return draft_ffdhe8192; + default: + return null; + } + } + + public static boolean containsDHCipherSuites(int[] cipherSuites) + { + for (int i = 0; i < cipherSuites.length; ++i) + { + if (isDHCipherSuite(cipherSuites[i])) + { + return true; + } + } + return false; + } + + public static boolean isDHCipherSuite(int cipherSuite) + { + switch (TlsUtils.getKeyExchangeAlgorithm(cipherSuite)) + { + case KeyExchangeAlgorithm.DH_anon: + case KeyExchangeAlgorithm.DH_anon_EXPORT: + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DH_DSS_EXPORT: + case KeyExchangeAlgorithm.DH_RSA: + case KeyExchangeAlgorithm.DH_RSA_EXPORT: + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_DSS_EXPORT: + case KeyExchangeAlgorithm.DHE_PSK: + case KeyExchangeAlgorithm.DHE_RSA: + case KeyExchangeAlgorithm.DHE_RSA_EXPORT: + return true; + + default: + return false; + } + } + + public static TlsDHConfig readDHConfig(InputStream input) throws IOException + { + BigInteger p = readDHParameter(input); + BigInteger g = readDHParameter(input); + + TlsDHConfig result = new TlsDHConfig(); + result.setExplicitPG(new BigInteger[]{ p, g }); + return result; + } + + public static TlsDHConfig receiveDHConfig(TlsDHConfigVerifier dhConfigVerifier, InputStream input) throws IOException + { + TlsDHConfig dhConfig = TlsDHUtils.readDHConfig(input); + if (!dhConfigVerifier.accept(dhConfig)) + { + throw new TlsFatalAlert(AlertDescription.insufficient_security); + } + return dhConfig; + } + + public static BigInteger readDHParameter(InputStream input) throws IOException + { + return new BigInteger(1, TlsUtils.readOpaque16(input)); + } + + public static TlsDHConfig selectDHConfig(DHGroup DHGroup) + { + TlsDHConfig result = new TlsDHConfig(); + result.setExplicitPG(new BigInteger[]{ DHGroup.getP(), DHGroup.getG() }); + return result; + } + + public static void validateDHPublicValues(BigInteger y, BigInteger p) throws IOException + { + if (y.compareTo(TWO) < 0 || y.compareTo(p.subtract(TWO)) > 0) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + // TODO See RFC 2631 for more discussion of Diffie-Hellman validation + } + + public static void writeDHConfig(TlsDHConfig dhConfig, OutputStream output) + throws IOException + { + BigInteger[] pg = dhConfig.getExplicitPG(); + writeDHParameter(pg[0], output); + writeDHParameter(pg[1], output); + } + + public static void writeDHParameter(BigInteger x, OutputStream output) throws IOException + { + TlsUtils.writeOpaque16(BigIntegers.asUnsignedByteArray(x), output); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsECConfigVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsECConfigVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsECConfigVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsECConfigVerifier.java 2016-07-21 03:43:53.000000000 +0000 @@ -0,0 +1,14 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsECConfig; + +public interface TlsECConfigVerifier +{ + /** + * Check whether the given EC configuration is acceptable for use. + * + * @param ecConfig the {@link TlsECConfig} to check + * @return true if (and only if) the specified configuration is acceptable + */ + boolean accept(TlsECConfig ecConfig); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsECCUtils.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsECCUtils.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsECCUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsECCUtils.java 2016-10-10 01:18:05.000000000 +0000 @@ -0,0 +1,350 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Hashtable; +import java.util.Set; + +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Integers; + +public class TlsECCUtils +{ + public static final Integer EXT_elliptic_curves = Integers.valueOf(ExtensionType.supported_groups); + public static final Integer EXT_ec_point_formats = Integers.valueOf(ExtensionType.ec_point_formats); + + public static void addSupportedEllipticCurvesExtension(Hashtable extensions, int[] namedCurves) throws IOException + { + extensions.put(EXT_elliptic_curves, createSupportedEllipticCurvesExtension(namedCurves)); + } + + public static void addSupportedPointFormatsExtension(Hashtable extensions, short[] ecPointFormats) + throws IOException + { + extensions.put(EXT_ec_point_formats, createSupportedPointFormatsExtension(ecPointFormats)); + } + + public static int[] getSupportedEllipticCurvesExtension(Hashtable extensions, Set acceptedCurves) throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_elliptic_curves); + return extensionData == null ? null : readSupportedEllipticCurvesExtension(extensionData, acceptedCurves); + } + + public static short[] getSupportedPointFormatsExtension(Hashtable extensions) throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_ec_point_formats); + return extensionData == null ? null : readSupportedPointFormatsExtension(extensionData); + } + + public static byte[] createSupportedEllipticCurvesExtension(int[] namedCurves) throws IOException + { + if (namedCurves == null || namedCurves.length < 1) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + return TlsUtils.encodeUint16ArrayWithUint16Length(namedCurves); + } + + public static byte[] createSupportedPointFormatsExtension(short[] ecPointFormats) throws IOException + { + if (ecPointFormats == null || !Arrays.contains(ecPointFormats, ECPointFormat.uncompressed)) + { + /* + * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST + * contain the value 0 (uncompressed) as one of the items in the list of point formats. + */ + + // NOTE: We add it at the end (lowest preference) + ecPointFormats = Arrays.append(ecPointFormats, ECPointFormat.uncompressed); + } + + return TlsUtils.encodeUint8ArrayWithUint8Length(ecPointFormats); + } + + public static int[] readSupportedEllipticCurvesExtension(byte[] extensionData, Set acceptedCurves) throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(extensionData); + + int length = TlsUtils.readUint16(buf); + if (length < 2 || (length & 1) != 0) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + int[] namedCurves = TlsUtils.readUint16Array(length / 2, buf); + + TlsProtocol.assertEmpty(buf); + + // + // check the proposed list is acceptable + // + int count = 0; + for (int i = 0; i != namedCurves.length; i++) + { + if (acceptedCurves.contains(namedCurves[i])) + { + count++; + } + } + + if (count == 0) + { + return null; + } + + // prune list if necessary + if (count != namedCurves.length) + { + int ind = 0; + int[] acceptedNamedCurves = new int[count]; + for (int i = 0; i != namedCurves.length; i++) + { + if (acceptedCurves.contains(namedCurves[i])) + { + acceptedNamedCurves[ind++] = namedCurves[i]; + } + } + + return acceptedNamedCurves; + } + + return namedCurves; + } + + public static short[] readSupportedPointFormatsExtension(byte[] extensionData) throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(extensionData); + + short length = TlsUtils.readUint8(buf); + if (length < 1) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + short[] ecPointFormats = TlsUtils.readUint8Array(length, buf); + + TlsProtocol.assertEmpty(buf); + + if (!Arrays.contains(ecPointFormats, ECPointFormat.uncompressed)) + { + /* + * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST + * contain the value 0 (uncompressed) as one of the items in the list of point formats. + */ + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + return ecPointFormats; + } + + public static boolean containsECCipherSuites(int[] cipherSuites) + { + for (int i = 0; i < cipherSuites.length; ++i) + { + if (isECCipherSuite(cipherSuites[i])) + { + return true; + } + } + return false; + } + + public static int getMinimumCurveBits(int cipherSuite) + { + switch (cipherSuite) + { + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256: + return 255; + + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_8_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384: + return 384; + + default: + { + if (!isECCipherSuite(cipherSuite)) + { + return 0; + } + + // TODO Is there a de facto rule to require a curve of similar size to the PRF hash? + return 1; + } + } + } + + public static boolean isECCipherSuite(int cipherSuite) + { + switch (TlsUtils.getKeyExchangeAlgorithm(cipherSuite)) + { + case KeyExchangeAlgorithm.ECDH_anon: + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDH_RSA: + case KeyExchangeAlgorithm.ECDHE_ECDSA: + case KeyExchangeAlgorithm.ECDHE_PSK: + case KeyExchangeAlgorithm.ECDHE_RSA: + return true; + + default: + return false; + } + } + + public static short getCompressionFormat(int namedCurve) throws IOException + { + if (NamedCurve.isPrime(namedCurve)) + { + return ECPointFormat.ansiX962_compressed_prime; + } + if (NamedCurve.isChar2(namedCurve)) + { + return ECPointFormat.ansiX962_compressed_char2; + } + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + public static boolean isCompressionPreferred(short[] peerECPointFormats, int namedCurve) throws IOException + { + return isCompressionPreferred(peerECPointFormats, getCompressionFormat(namedCurve)); + } + + public static boolean isCompressionPreferred(short[] peerECPointFormats, short compressionFormat) + { + if (peerECPointFormats == null || compressionFormat == ECPointFormat.uncompressed) + { + return false; + } + for (int i = 0; i < peerECPointFormats.length; ++i) + { + short ecPointFormat = peerECPointFormats[i]; + if (ecPointFormat == ECPointFormat.uncompressed) + { + return false; + } + if (ecPointFormat == compressionFormat) + { + return true; + } + } + return false; + } + + public static void checkPointEncoding(short[] localECPointFormats, int namedCurve, byte[] encoding) throws IOException + { + if (encoding == null || encoding.length < 1) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + short actualFormat = getActualFormat(namedCurve, encoding); + checkActualFormat(localECPointFormats, actualFormat); + } + + public static void checkActualFormat(short[] localECPointFormats, short actualFormat) throws IOException + { + if (actualFormat != ECPointFormat.uncompressed + && (localECPointFormats == null || !Arrays.contains(localECPointFormats, actualFormat))) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + + public static short getActualFormat(int namedCurve, byte[] encoding) throws IOException + { + switch (encoding[0]) + { + case 0x02: // compressed + case 0x03: // compressed + { + return getCompressionFormat(namedCurve); + } + case 0x04: // uncompressed + { + return ECPointFormat.uncompressed; + } + case 0x00: // infinity + case 0x06: // hybrid + case 0x07: // hybrid + default: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + + public static TlsECConfig readECConfig(short[] peerECPointFormats, InputStream input) + throws IOException + { + short curveType = TlsUtils.readUint8(input); + if (curveType != ECCurveType.named_curve) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + int namedCurve = TlsUtils.readUint16(input); + if (!NamedCurve.refersToASpecificNamedCurve(namedCurve)) + { + /* + * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a + * specific curve. Values of NamedCurve that indicate support for a class of + * explicitly defined curves are not allowed here [...]. + */ + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + boolean compressed = isCompressionPreferred(peerECPointFormats, namedCurve); + + TlsECConfig result = new TlsECConfig(); + result.setNamedCurve(namedCurve); + result.setPointCompression(compressed); + return result; + } + + public static TlsECConfig receiveECConfig(TlsECConfigVerifier ecConfigVerifier, short[] peerECPointFormats, InputStream input) + throws IOException + { + TlsECConfig ecConfig = readECConfig(peerECPointFormats, input); + if (!ecConfigVerifier.accept(ecConfig)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + return ecConfig; + } + + public static void writeECConfig(TlsECConfig ecConfig, OutputStream output) throws IOException + { + writeNamedECParameters(ecConfig.getNamedCurve(), output); + } + + public static void writeNamedECParameters(int namedCurve, OutputStream output) throws IOException + { + if (!NamedCurve.refersToASpecificNamedCurve(namedCurve)) + { + /* + * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a specific + * curve. Values of NamedCurve that indicate support for a class of explicitly defined + * curves are not allowed here [...]. + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + TlsUtils.writeUint8(ECCurveType.named_curve, output); + TlsUtils.checkUint16(namedCurve); + TlsUtils.writeUint16(namedCurve, output); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsECDHEKeyExchange.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsECDHEKeyExchange.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsECDHEKeyExchange.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsECDHEKeyExchange.java 2016-10-05 02:02:00.000000000 +0000 @@ -0,0 +1,137 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.tls.crypto.TlsVerifier; +import org.bouncycastle.util.io.TeeInputStream; + +/** + * (D)TLS ECDHE key exchange (see RFC 4492). + */ +public class TlsECDHEKeyExchange + extends TlsECDHKeyExchange +{ + private static int checkKeyExchange(int keyExchange) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.ECDHE_ECDSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + return keyExchange; + default: + throw new IllegalArgumentException("unsupported key exchange algorithm"); + } + } + + protected TlsCredentialedSigner serverCredentials = null; + protected TlsVerifier verifier = null; + + public TlsECDHEKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfigVerifier ecConfigVerifier, short[] clientECPointFormats, short[] serverECPointFormats) + { + super(checkKeyExchange(keyExchange), supportedSignatureAlgorithms, ecConfigVerifier, clientECPointFormats, + serverECPointFormats); + } + + public TlsECDHEKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsECConfig ecConfig, + short[] serverECPointFormats) + { + super(checkKeyExchange(keyExchange), supportedSignatureAlgorithms, ecConfig, serverECPointFormats); + } + + public void processServerCredentials(TlsCredentials serverCredentials) throws IOException + { + if (!(serverCredentials instanceof TlsCredentialedSigner)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.serverCredentials = (TlsCredentialedSigner)serverCredentials; + } + + public void processServerCertificate(Certificate serverCertificate) throws IOException + { + if (serverCertificate.isEmpty()) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + checkServerCertSigAlg(serverCertificate); + + this.verifier = serverCertificate.getCertificateAt(0) + .createVerifier(TlsUtils.getSignatureAlgorithm(keyExchange)); + } + + public byte[] generateServerKeyExchange() throws IOException + { + DigestInputBuffer buf = new DigestInputBuffer(); + + TlsECCUtils.writeECConfig(ecConfig, buf); + + this.agreement = context.getCrypto().createECDomain(ecConfig).createECDH(); + + generateEphemeral(buf); + + DigitallySigned signedParams = TlsUtils.generateServerKeyExchangeSignature(context, serverCredentials, buf); + + signedParams.encode(buf); + + return buf.toByteArray(); + } + + public void processServerKeyExchange(InputStream input) throws IOException + { + DigestInputBuffer buf = new DigestInputBuffer(); + InputStream teeIn = new TeeInputStream(input, buf); + + this.ecConfig = TlsECCUtils.receiveECConfig(ecConfigVerifier, serverECPointFormats, teeIn); + + byte[] point = TlsUtils.readOpaque8(teeIn); + + DigitallySigned signedParams = parseSignature(input); + + TlsUtils.verifyServerKeyExchangeSignature(context, verifier, buf, signedParams); + + this.agreement = context.getCrypto().createECDomain(ecConfig).createECDH(); + + processEphemeral(clientECPointFormats, point); + } + + public void validateCertificateRequest(CertificateRequest certificateRequest) throws IOException + { + /* + * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with + * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because + * the use of a long-term ECDH client key would jeopardize the forward secrecy property of + * these algorithms. + */ + short[] types = certificateRequest.getCertificateTypes(); + for (int i = 0; i < types.length; ++i) + { + switch (types[i]) + { + case ClientCertificateType.dss_sign: + case ClientCertificateType.ecdsa_sign: + case ClientCertificateType.rsa_sign: + break; + default: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + public void processClientCredentials(TlsCredentials clientCredentials) throws IOException + { + if (clientCredentials instanceof TlsCredentialedSigner) + { + // OK + } + else + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsECDHKeyExchange.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsECDHKeyExchange.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsECDHKeyExchange.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsECDHKeyExchange.java 2016-11-01 20:33:01.000000000 +0000 @@ -0,0 +1,272 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.tls.crypto.TlsSecret; + +/** + * (D)TLS ECDH key exchange (see RFC 4492). + */ +public class TlsECDHKeyExchange + extends AbstractTlsKeyExchange +{ + private static int checkKeyExchange(int keyExchange) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.ECDH_anon: + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDH_RSA: + case KeyExchangeAlgorithm.ECDHE_ECDSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + return keyExchange; + default: + throw new IllegalArgumentException("unsupported key exchange algorithm"); + } + } + + protected TlsECConfigVerifier ecConfigVerifier; + protected short[] clientECPointFormats, serverECPointFormats; + + protected TlsCredentialedAgreement agreementCredentials; + protected TlsCertificate ecdhPeerCertificate; + + protected TlsECConfig ecConfig; + protected TlsAgreement agreement; + + public TlsECDHKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfigVerifier ecConfigVerifier, short[] clientECPointFormats, short[] serverECPointFormats) + { + this(keyExchange, supportedSignatureAlgorithms, ecConfigVerifier, null, clientECPointFormats, + serverECPointFormats); + } + + public TlsECDHKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsECConfig ecConfig, + short[] serverECPointFormats) + { + this(keyExchange, supportedSignatureAlgorithms, null, ecConfig, null, serverECPointFormats); + } + + private TlsECDHKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfigVerifier ecConfigVerifier, TlsECConfig ecConfig, short[] clientECPointFormats, + short[] serverECPointFormats) + { + super(checkKeyExchange(keyExchange), supportedSignatureAlgorithms); + + this.ecConfigVerifier = ecConfigVerifier; + this.ecConfig = ecConfig; + this.clientECPointFormats = clientECPointFormats; + this.serverECPointFormats = serverECPointFormats; + } + + public void skipServerCredentials() throws IOException + { + if (keyExchange != KeyExchangeAlgorithm.ECDH_anon) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public void processServerCredentials(TlsCredentials serverCredentials) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.ECDH_anon) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + if (!(serverCredentials instanceof TlsCredentialedAgreement)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.agreementCredentials = (TlsCredentialedAgreement)serverCredentials; + } + + public void processServerCertificate(Certificate serverCertificate) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.ECDH_anon) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + checkServerCertSigAlg(serverCertificate); + + this.ecdhPeerCertificate = validatePeerCertificate(ConnectionEnd.server, serverCertificate); + } + + public boolean requiresServerKeyExchange() + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.ECDH_anon: + case KeyExchangeAlgorithm.ECDHE_ECDSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + return true; + default: + return false; + } + } + + public byte[] generateServerKeyExchange() throws IOException + { + if (!requiresServerKeyExchange()) + { + return null; + } + + // ECDH_anon is handled here, ECDHE_* in a subclass + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + TlsECCUtils.writeECConfig(ecConfig, buf); + + this.agreement = context.getCrypto().createECDomain(ecConfig).createECDH(); + + generateEphemeral(buf); + + return buf.toByteArray(); + } + + public void processServerKeyExchange(InputStream input) throws IOException + { + if (!requiresServerKeyExchange()) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + // ECDH_anon is handled here, ECDHE_* in a subclass + + this.ecConfig = TlsECCUtils.receiveECConfig(ecConfigVerifier, serverECPointFormats, input); + + byte[] point = TlsUtils.readOpaque8(input); + + this.agreement = context.getCrypto().createECDomain(ecConfig).createECDH(); + + processEphemeral(clientECPointFormats, point); + } + + public void validateCertificateRequest(CertificateRequest certificateRequest) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.ECDH_anon) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + /* + * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with + * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because + * the use of a long-term ECDH client key would jeopardize the forward secrecy property of + * these algorithms. + */ + short[] types = certificateRequest.getCertificateTypes(); + for (int i = 0; i < types.length; ++i) + { + switch (types[i]) + { + case ClientCertificateType.ecdsa_fixed_ecdh: + case ClientCertificateType.rsa_fixed_ecdh: + break; + default: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + public void processClientCredentials(TlsCredentials clientCredentials) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.ECDH_anon) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + if (clientCredentials instanceof TlsCredentialedAgreement) + { + this.agreementCredentials = (TlsCredentialedAgreement)clientCredentials; + + // TODO Check that the client certificate's domain parameters match the server's? + } + else + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public void generateClientKeyExchange(OutputStream output) throws IOException + { + if (agreementCredentials == null) + { + generateEphemeral(output); + } + } + + public void processClientCertificate(Certificate clientCertificate) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.ECDH_anon) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + if (agreementCredentials != null) + { + // TODO[tls-ops] Where to check that the domain parameters match the server's? + this.ecdhPeerCertificate = validatePeerCertificate(ConnectionEnd.client, clientCertificate); + } + } + + public void processClientKeyExchange(InputStream input) throws IOException + { + if (ecdhPeerCertificate != null) + { + // For ecdsa_fixed_ecdh and rsa_fixed_ecdh, the key arrived in the client certificate + return; + } + + byte[] point = TlsUtils.readOpaque8(input); + + processEphemeral(serverECPointFormats, point); + } + + public TlsSecret generatePreMasterSecret() throws IOException + { + if (agreementCredentials != null) + { + return agreementCredentials.generateAgreement(ecdhPeerCertificate); + } + + if (agreement != null) + { + return agreement.calculateSecret(); + } + + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected void generateEphemeral(OutputStream output) throws IOException + { + byte[] point = agreement.generateEphemeral(); + TlsUtils.writeOpaque8(point, output); + } + + protected void processEphemeral(short[] localECPointFormats, byte[] point) throws IOException + { + TlsECCUtils.checkPointEncoding(localECPointFormats, ecConfig.getNamedCurve(), point); + + this.agreement.receivePeerValue(point); + } + + protected TlsCertificate validatePeerCertificate(int connectionEnd, Certificate peerCertificate) throws IOException + { + if (peerCertificate.isEmpty()) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + return peerCertificate.getCertificateAt(0).useInRole(connectionEnd, keyExchange); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsExtensionsUtils.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsExtensionsUtils.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsExtensionsUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsExtensionsUtils.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,319 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Hashtable; + +import org.bouncycastle.util.Integers; + +public class TlsExtensionsUtils +{ + public static final Integer EXT_encrypt_then_mac = Integers.valueOf(ExtensionType.encrypt_then_mac); + public static final Integer EXT_extended_master_secret = Integers.valueOf(ExtensionType.extended_master_secret); + public static final Integer EXT_heartbeat = Integers.valueOf(ExtensionType.heartbeat); + public static final Integer EXT_max_fragment_length = Integers.valueOf(ExtensionType.max_fragment_length); + public static final Integer EXT_padding = Integers.valueOf(ExtensionType.padding); + public static final Integer EXT_server_name = Integers.valueOf(ExtensionType.server_name); + public static final Integer EXT_status_request = Integers.valueOf(ExtensionType.status_request); + public static final Integer EXT_truncated_hmac = Integers.valueOf(ExtensionType.truncated_hmac); + + public static Hashtable ensureExtensionsInitialised(Hashtable extensions) + { + return extensions == null ? new Hashtable() : extensions; + } + + public static void addEncryptThenMACExtension(Hashtable extensions) + { + extensions.put(EXT_encrypt_then_mac, createEncryptThenMACExtension()); + } + + public static void addExtendedMasterSecretExtension(Hashtable extensions) + { + extensions.put(EXT_extended_master_secret, createExtendedMasterSecretExtension()); + } + + public static void addHeartbeatExtension(Hashtable extensions, HeartbeatExtension heartbeatExtension) + throws IOException + { + extensions.put(EXT_heartbeat, createHeartbeatExtension(heartbeatExtension)); + } + + public static void addMaxFragmentLengthExtension(Hashtable extensions, short maxFragmentLength) + throws IOException + { + extensions.put(EXT_max_fragment_length, createMaxFragmentLengthExtension(maxFragmentLength)); + } + + public static void addPaddingExtension(Hashtable extensions, int dataLength) + throws IOException + { + extensions.put(EXT_padding, createPaddingExtension(dataLength)); + } + + public static void addServerNameExtension(Hashtable extensions, ServerNameList serverNameList) + throws IOException + { + extensions.put(EXT_server_name, createServerNameExtension(serverNameList)); + } + + public static void addStatusRequestExtension(Hashtable extensions, CertificateStatusRequest statusRequest) + throws IOException + { + extensions.put(EXT_status_request, createStatusRequestExtension(statusRequest)); + } + + public static void addTruncatedHMacExtension(Hashtable extensions) + { + extensions.put(EXT_truncated_hmac, createTruncatedHMacExtension()); + } + + public static HeartbeatExtension getHeartbeatExtension(Hashtable extensions) + throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_heartbeat); + return extensionData == null ? null : readHeartbeatExtension(extensionData); + } + + public static short getMaxFragmentLengthExtension(Hashtable extensions) + throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_max_fragment_length); + return extensionData == null ? -1 : readMaxFragmentLengthExtension(extensionData); + } + + public static int getPaddingExtension(Hashtable extensions) + throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_padding); + return extensionData == null ? -1 : readPaddingExtension(extensionData); + } + + public static ServerNameList getServerNameExtension(Hashtable extensions) + throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_server_name); + return extensionData == null ? null : readServerNameExtension(extensionData); + } + + public static CertificateStatusRequest getStatusRequestExtension(Hashtable extensions) + throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_status_request); + return extensionData == null ? null : readStatusRequestExtension(extensionData); + } + + public static boolean hasEncryptThenMACExtension(Hashtable extensions) throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_encrypt_then_mac); + return extensionData == null ? false : readEncryptThenMACExtension(extensionData); + } + + public static boolean hasExtendedMasterSecretExtension(Hashtable extensions) throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_extended_master_secret); + return extensionData == null ? false : readExtendedMasterSecretExtension(extensionData); + } + + public static boolean hasTruncatedHMacExtension(Hashtable extensions) throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_truncated_hmac); + return extensionData == null ? false : readTruncatedHMacExtension(extensionData); + } + + public static byte[] createEmptyExtensionData() + { + return TlsUtils.EMPTY_BYTES; + } + + public static byte[] createEncryptThenMACExtension() + { + return createEmptyExtensionData(); + } + + public static byte[] createExtendedMasterSecretExtension() + { + return createEmptyExtensionData(); + } + + public static byte[] createHeartbeatExtension(HeartbeatExtension heartbeatExtension) + throws IOException + { + if (heartbeatExtension == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + heartbeatExtension.encode(buf); + + return buf.toByteArray(); + } + + public static byte[] createMaxFragmentLengthExtension(short maxFragmentLength) + throws IOException + { + TlsUtils.checkUint8(maxFragmentLength); + + byte[] extensionData = new byte[1]; + TlsUtils.writeUint8(maxFragmentLength, extensionData, 0); + return extensionData; + } + + public static byte[] createPaddingExtension(int dataLength) + throws IOException + { + TlsUtils.checkUint16(dataLength); + return new byte[dataLength]; + } + + public static byte[] createServerNameExtension(ServerNameList serverNameList) + throws IOException + { + if (serverNameList == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + serverNameList.encode(buf); + + return buf.toByteArray(); + } + + public static byte[] createStatusRequestExtension(CertificateStatusRequest statusRequest) + throws IOException + { + if (statusRequest == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + statusRequest.encode(buf); + + return buf.toByteArray(); + } + + public static byte[] createTruncatedHMacExtension() + { + return createEmptyExtensionData(); + } + + private static boolean readEmptyExtensionData(byte[] extensionData) throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + if (extensionData.length != 0) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + return true; + } + + public static boolean readEncryptThenMACExtension(byte[] extensionData) throws IOException + { + return readEmptyExtensionData(extensionData); + } + + public static boolean readExtendedMasterSecretExtension(byte[] extensionData) throws IOException + { + return readEmptyExtensionData(extensionData); + } + + public static HeartbeatExtension readHeartbeatExtension(byte[] extensionData) + throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(extensionData); + + HeartbeatExtension heartbeatExtension = HeartbeatExtension.parse(buf); + + TlsProtocol.assertEmpty(buf); + + return heartbeatExtension; + } + + public static short readMaxFragmentLengthExtension(byte[] extensionData) + throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + if (extensionData.length != 1) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + return TlsUtils.readUint8(extensionData, 0); + } + + public static int readPaddingExtension(byte[] extensionData) + throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + for (int i = 0; i < extensionData.length; ++i) + { + if (extensionData[i] != 0) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + return extensionData.length; + } + + public static ServerNameList readServerNameExtension(byte[] extensionData) + throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(extensionData); + + ServerNameList serverNameList = ServerNameList.parse(buf); + + TlsProtocol.assertEmpty(buf); + + return serverNameList; + } + + public static CertificateStatusRequest readStatusRequestExtension(byte[] extensionData) + throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(extensionData); + + CertificateStatusRequest statusRequest = CertificateStatusRequest.parse(buf); + + TlsProtocol.assertEmpty(buf); + + return statusRequest; + } + + public static boolean readTruncatedHMacExtension(byte[] extensionData) throws IOException + { + return readEmptyExtensionData(extensionData); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsFatalAlert.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsFatalAlert.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsFatalAlert.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsFatalAlert.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,37 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +public class TlsFatalAlert + extends IOException +{ + private static final long serialVersionUID = 3584313123679111168L; + + protected short alertDescription; + + // TODO Some day we might be able to just pass this down to IOException (1.6+) + protected Throwable alertCause; + + public TlsFatalAlert(short alertDescription) + { + this(alertDescription, null); + } + + public TlsFatalAlert(short alertDescription, Throwable alertCause) + { + super(AlertDescription.getText(alertDescription)); + + this.alertDescription = alertDescription; + this.alertCause = alertCause; + } + + public short getAlertDescription() + { + return alertDescription; + } + + public Throwable getCause() + { + return alertCause; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsHandshakeHash.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsHandshakeHash.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsHandshakeHash.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsHandshakeHash.java 2016-08-28 05:18:57.000000000 +0000 @@ -0,0 +1,19 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsHash; + +public interface TlsHandshakeHash + extends TlsHash +{ + TlsHandshakeHash notifyPRFDetermined(); + + void trackHashAlgorithm(short hashAlgorithm); + + void sealHashAlgorithms(); + + TlsHandshakeHash stopTracking(); + + TlsHash forkPRFHash(); + + byte[] getFinalHash(short hashAlgorithm); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsInputStream.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsInputStream.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsInputStream.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsInputStream.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,47 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; + +/** + * An InputStream for an TLS 1.0 connection. + */ +class TlsInputStream + extends InputStream +{ + private byte[] buf = new byte[1]; + private TlsProtocol handler = null; + + TlsInputStream(TlsProtocol handler) + { + this.handler = handler; + } + + public int available() + throws IOException + { + return this.handler.applicationDataAvailable(); + } + + public int read(byte[] buf, int offset, int len) + throws IOException + { + return this.handler.readApplicationData(buf, offset, len); + } + + public int read() + throws IOException + { + if (this.read(buf) < 0) + { + return -1; + } + return buf[0] & 0xff; + } + + public void close() + throws IOException + { + handler.close(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchangeFactory.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchangeFactory.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchangeFactory.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchangeFactory.java 2016-08-28 04:49:25.000000000 +0000 @@ -0,0 +1,52 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsECConfig; + +public interface TlsKeyExchangeFactory +{ + TlsKeyExchange createDHKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsDHConfigVerifier dhConfigVerifier) throws IOException; + + TlsKeyExchange createDHKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, TlsDHConfig dhConfig) + throws IOException; + + TlsKeyExchange createDHEKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsDHConfigVerifier dhConfigVerifier) throws IOException; + + TlsKeyExchange createDHEKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsDHConfig dhConfig) throws IOException; + + TlsKeyExchange createECDHKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfigVerifier ecConfigVerifier, short[] clientECPointFormats, short[] serverECPointFormats) + throws IOException; + + TlsKeyExchange createECDHKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfig ecConfig, short[] serverECPointFormats) throws IOException; + + TlsKeyExchange createECDHEKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfigVerifier ecConfigVerifier, short[] clientECPointFormats, short[] serverECPointFormats) + throws IOException; + + TlsKeyExchange createECDHEKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsECConfig ecConfig, short[] serverECPointFormats) throws IOException; + + TlsKeyExchange createPSKKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsPSKIdentity pskIdentity, TlsDHConfigVerifier dhConfigVerifier, TlsECConfigVerifier ecConfigVerifier, + short[] clientECPointFormats, short[] serverECPointFormats) throws IOException; + + TlsKeyExchange createPSKKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, + TlsPSKIdentityManager pskIdentityManager, TlsDHConfig dhConfig, TlsECConfig ecConfig, + short[] serverECPointFormats) throws IOException; + + TlsKeyExchange createRSAKeyExchange(Vector supportedSignatureAlgorithms) throws IOException; + + TlsKeyExchange createSRPKeyExchangeClient(int keyExchange, Vector supportedSignatureAlgorithms, + TlsSRPConfigVerifier srpConfigVerifier, byte[] identity, byte[] password) throws IOException; + + TlsKeyExchange createSRPKeyExchangeServer(int keyExchange, Vector supportedSignatureAlgorithms, byte[] identity, + TlsSRPLoginParameters loginParameters) throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchange.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchange.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchange.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchange.java 2016-07-04 21:36:38.000000000 +0000 @@ -0,0 +1,56 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.bouncycastle.tls.crypto.TlsSecret; + +/** + * A generic interface for key exchange implementations in (D)TLS. + */ +public interface TlsKeyExchange +{ + void init(TlsContext context); + + void skipServerCredentials() + throws IOException; + + void processServerCredentials(TlsCredentials serverCredentials) + throws IOException; + + void processServerCertificate(Certificate serverCertificate) + throws IOException; + + boolean requiresServerKeyExchange(); + + byte[] generateServerKeyExchange() + throws IOException; + + void skipServerKeyExchange() + throws IOException; + + void processServerKeyExchange(InputStream input) + throws IOException; + + void validateCertificateRequest(CertificateRequest certificateRequest) + throws IOException; + + void skipClientCredentials() + throws IOException; + + void processClientCredentials(TlsCredentials clientCredentials) + throws IOException; + + void processClientCertificate(Certificate clientCertificate) + throws IOException; + + void generateClientKeyExchange(OutputStream output) + throws IOException; + + void processClientKeyExchange(InputStream input) + throws IOException; + + TlsSecret generatePreMasterSecret() + throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsNullCompression.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsNullCompression.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsNullCompression.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsNullCompression.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,17 @@ +package org.bouncycastle.tls; + +import java.io.OutputStream; + +public class TlsNullCompression + implements TlsCompression +{ + public OutputStream compress(OutputStream output) + { + return output; + } + + public OutputStream decompress(OutputStream output) + { + return output; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsOutputStream.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsOutputStream.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsOutputStream.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsOutputStream.java 2016-11-28 10:06:34.000000000 +0000 @@ -0,0 +1,44 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * An OutputStream for an TLS connection. + */ +class TlsOutputStream + extends OutputStream +{ + private byte[] buf = new byte[1]; + private TlsProtocol handler; + + TlsOutputStream(TlsProtocol handler) + { + this.handler = handler; + } + + public void write(byte buf[], int offset, int len) + throws IOException + { + this.handler.writeApplicationData(buf, offset, len); + } + + public void write(int arg0) + throws IOException + { + buf[0] = (byte)arg0; + this.write(buf, 0, 1); + } + + public void close() + throws IOException + { + handler.close(); + } + + public void flush() + throws IOException + { + handler.flush(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsPeer.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsPeer.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsPeer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsPeer.java 2016-11-22 03:47:04.000000000 +0000 @@ -0,0 +1,54 @@ +package org.bouncycastle.tls; + +import java.io.IOException; + +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCrypto; + +/** + * Base interface for a TLS endpoint. + */ +public interface TlsPeer +{ + TlsCrypto getCrypto(); + + /** + * draft-mathewson-no-gmtunixtime-00 2. "If existing users of a TLS implementation may rely on + * gmt_unix_time containing the current time, we recommend that implementors MAY provide the + * ability to set gmt_unix_time as an option only, off by default." + * + * @return true if the current time should be used in the gmt_unix_time field of + * Random, or false if gmt_unix_time should contain a cryptographically + * random value. + */ + boolean shouldUseGMTUnixTime(); + + void notifySecureRenegotiation(boolean secureNegotiation) throws IOException; + + TlsCompression getCompression() throws IOException; + + TlsCipher getCipher() throws IOException; + + /** + * This method will be called when an alert is raised by the protocol. + * + * @param alertLevel {@link AlertLevel} + * @param alertDescription {@link AlertDescription} + * @param message A human-readable message explaining what caused this alert. May be null. + * @param cause The {@link Throwable} that caused this alert to be raised. May be null. + */ + void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause); + + /** + * This method will be called when an alert is received from the remote peer. + * + * @param alertLevel {@link AlertLevel} + * @param alertDescription {@link AlertDescription} + */ + void notifyAlertReceived(short alertLevel, short alertDescription); + + /** + * Notifies the peer that the handshake has been successfully completed. + */ + void notifyHandshakeComplete() throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsProtocol.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsProtocol.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsProtocol.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsProtocol.java 2016-11-28 10:06:34.000000000 +0000 @@ -0,0 +1,1510 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsHash; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Integers; + +public abstract class TlsProtocol +{ + protected static final Integer EXT_RenegotiationInfo = Integers.valueOf(ExtensionType.renegotiation_info); + protected static final Integer EXT_SessionTicket = Integers.valueOf(ExtensionType.session_ticket); + + private static final String TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack"; + + /* + * Our Connection states + */ + protected static final short CS_START = 0; + protected static final short CS_CLIENT_HELLO = 1; + protected static final short CS_SERVER_HELLO = 2; + protected static final short CS_SERVER_SUPPLEMENTAL_DATA = 3; + protected static final short CS_SERVER_CERTIFICATE = 4; + protected static final short CS_CERTIFICATE_STATUS = 5; + protected static final short CS_SERVER_KEY_EXCHANGE = 6; + protected static final short CS_CERTIFICATE_REQUEST = 7; + protected static final short CS_SERVER_HELLO_DONE = 8; + protected static final short CS_CLIENT_SUPPLEMENTAL_DATA = 9; + protected static final short CS_CLIENT_CERTIFICATE = 10; + protected static final short CS_CLIENT_KEY_EXCHANGE = 11; + protected static final short CS_CERTIFICATE_VERIFY = 12; + protected static final short CS_CLIENT_FINISHED = 13; + protected static final short CS_SERVER_SESSION_TICKET = 14; + protected static final short CS_SERVER_FINISHED = 15; + protected static final short CS_END = 16; + + /* + * Different modes to handle the known IV weakness + */ + protected static final short ADS_MODE_1_Nsub1 = 0; // 1/n-1 record splitting + protected static final short ADS_MODE_0_N = 1; // 0/n record splitting + protected static final short ADS_MODE_0_N_FIRSTONLY = 2; // 0/n record splitting on first data fragment only + + /* + * Queues for data from some protocols. + */ + private ByteQueue applicationDataQueue = new ByteQueue(); + private ByteQueue alertQueue = new ByteQueue(2); + private ByteQueue handshakeQueue = new ByteQueue(); +// private ByteQueue heartbeatQueue = new ByteQueue(); + + /* + * The Record Stream we use + */ + RecordStream recordStream; + + private TlsInputStream tlsInputStream = null; + private TlsOutputStream tlsOutputStream = null; + + private volatile boolean closed = false; + private volatile boolean failedWithError = false; + private volatile boolean appDataReady = false; + private volatile boolean appDataSplitEnabled = true; + private volatile int appDataSplitMode = ADS_MODE_1_Nsub1; + // TODO[tls-ops] Investigate whether we can handle (expected/actual) verify data using TlsSecret + private byte[] expected_verify_data = null; + + protected TlsSession tlsSession = null; + protected SessionParameters sessionParameters = null; + protected SecurityParameters securityParameters = null; + protected Certificate localCertificate = null; + protected Certificate peerCertificate = null; + + protected int[] offeredCipherSuites = null; + protected short[] offeredCompressionMethods = null; + protected Hashtable clientExtensions = null; + protected Hashtable serverExtensions = null; + + protected short connection_state = CS_START; + protected boolean resumedSession = false; + protected boolean receivedChangeCipherSpec = false; + protected boolean secure_renegotiation = false; + protected boolean allowCertificateStatus = false; + protected boolean expectSessionTicket = false; + + protected boolean blocking; + protected ByteQueueInputStream inputBuffers; + protected ByteQueueOutputStream outputBuffer; + + protected TlsProtocol() + { + this.blocking = false; + this.inputBuffers = new ByteQueueInputStream(); + this.outputBuffer = new ByteQueueOutputStream(); + this.recordStream = new RecordStream(this, inputBuffers, outputBuffer); + } + + protected TlsProtocol(InputStream input, OutputStream output) + { + this.blocking = true; + this.recordStream = new RecordStream(this, input, output); + } + + protected abstract TlsContext getContext(); + + abstract AbstractTlsContext getContextAdmin(); + + protected abstract TlsPeer getPeer(); + + protected void handleChangeCipherSpecMessage() throws IOException + { + } + + protected abstract void handleHandshakeMessage(short type, byte[] buf) + throws IOException; + + protected void handleWarningMessage(short description) + throws IOException + { + } + + protected void applyMaxFragmentLengthExtension() + throws IOException + { + short maxFragmentLength = securityParameters.getMaxFragmentLength(); + if (maxFragmentLength >= 0) + { + if (!MaxFragmentLength.isValid(maxFragmentLength)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + int plainTextLimit = 1 << (8 + maxFragmentLength); + recordStream.setPlaintextLimit(plainTextLimit); + } + } + + protected void checkReceivedChangeCipherSpec(boolean expected) + throws IOException + { + if (expected != receivedChangeCipherSpec) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + } + + protected void cleanupHandshake() + { + if (this.expected_verify_data != null) + { + Arrays.fill(this.expected_verify_data, (byte)0); + this.expected_verify_data = null; + } + + this.tlsSession = null; + this.sessionParameters = null; + this.securityParameters.clear(); + this.localCertificate = null; + this.peerCertificate = null; + + this.offeredCipherSuites = null; + this.offeredCompressionMethods = null; + this.clientExtensions = null; + this.serverExtensions = null; + + this.resumedSession = false; + this.receivedChangeCipherSpec = false; + this.secure_renegotiation = false; + this.allowCertificateStatus = false; + this.expectSessionTicket = false; + } + + protected void blockForHandshake() throws IOException + { + if (blocking) + { + while (this.connection_state != CS_END) + { + if (this.closed) + { + // TODO What kind of exception/alert? + } + + safeReadRecord(); + } + } + } + + protected void completeHandshake() + throws IOException + { + try + { + this.recordStream.finaliseHandshake(); + + this.appDataSplitEnabled = !TlsUtils.isTLSv11(getContext()); + + /* + * If this was an initial handshake, we are now ready to send and receive application data. + */ + if (!appDataReady) + { + this.appDataReady = true; + + if (blocking) + { + this.tlsInputStream = new TlsInputStream(this); + this.tlsOutputStream = new TlsOutputStream(this); + } + } + + if (this.sessionParameters == null) + { + this.sessionParameters = new SessionParameters.Builder() + .setCipherSuite(this.securityParameters.getCipherSuite()) + .setCompressionAlgorithm(this.securityParameters.getCompressionAlgorithm()) + .setLocalCertificate(this.localCertificate) + .setMasterSecret(getContext().getCrypto().adoptSecret(this.securityParameters.getMasterSecret())) + .setNegotiatedVersion(getContext().getServerVersion()) + .setPeerCertificate(this.peerCertificate) + .setPSKIdentity(this.securityParameters.getPSKIdentity()) + .setSRPIdentity(this.securityParameters.getSRPIdentity()) + // TODO Consider filtering extensions that aren't relevant to resumed sessions + .setServerExtensions(this.serverExtensions) + .build(); + + this.tlsSession = TlsUtils.importSession(this.tlsSession.getSessionID(), this.sessionParameters); + } + + getContextAdmin().setSession(this.tlsSession); + + getPeer().notifyHandshakeComplete(); + } + finally + { + cleanupHandshake(); + } + } + + protected void processRecord(short protocol, byte[] buf, int offset, int len) + throws IOException + { + /* + * Have a look at the protocol type, and add it to the correct queue. + */ + switch (protocol) + { + case ContentType.alert: + { + alertQueue.addData(buf, offset, len); + processAlert(); + break; + } + case ContentType.application_data: + { + if (!appDataReady) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + applicationDataQueue.addData(buf, offset, len); + processApplicationData(); + break; + } + case ContentType.change_cipher_spec: + { + processChangeCipherSpec(buf, offset, len); + break; + } + case ContentType.handshake: + { + handshakeQueue.addData(buf, offset, len); + processHandshake(); + break; + } + case ContentType.heartbeat: + { + if (!appDataReady) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + // TODO[RFC 6520] +// heartbeatQueue.addData(buf, offset, len); +// processHeartbeat(); + break; + } + default: + /* + * Uh, we don't know this protocol. + * + * RFC2246 defines on page 13, that we should ignore this. + */ + break; + } + } + + private void processHandshake() + throws IOException + { + boolean read; + do + { + read = false; + /* + * We need the first 4 bytes, they contain type and length of the message. + */ + if (handshakeQueue.available() >= 4) + { + byte[] beginning = new byte[4]; + handshakeQueue.read(beginning, 0, 4, 0); + short type = TlsUtils.readUint8(beginning, 0); + int len = TlsUtils.readUint24(beginning, 1); + + /* + * Check if we have enough bytes in the buffer to read the full message. + */ + if (handshakeQueue.available() >= (len + 4)) + { + /* + * Read the message. + */ + byte[] buf = handshakeQueue.removeData(len, 4); + + checkReceivedChangeCipherSpec(connection_state == CS_END || type == HandshakeType.finished); + + /* + * RFC 2246 7.4.9. The value handshake_messages includes all handshake messages + * starting at client hello up to, but not including, this finished message. + * [..] Note: [Also,] Hello Request messages are omitted from handshake hashes. + */ + switch (type) + { + case HandshakeType.hello_request: + break; + case HandshakeType.finished: + { + TlsContext ctx = getContext(); + if (this.expected_verify_data == null + && ctx.getSecurityParameters().getMasterSecret() != null) + { + this.expected_verify_data = createVerifyData(!ctx.isServer()); + } + + // NB: Fall through to next case label + } + default: + recordStream.updateHandshakeData(beginning, 0, 4); + recordStream.updateHandshakeData(buf, 0, len); + break; + } + + /* + * Now, parse the message. + */ + handleHandshakeMessage(type, buf); + read = true; + } + } + } + while (read); + } + + private void processApplicationData() + { + /* + * There is nothing we need to do here. + * + * This function could be used for callbacks when application data arrives in the future. + */ + } + + private void processAlert() + throws IOException + { + while (alertQueue.available() >= 2) + { + /* + * An alert is always 2 bytes. Read the alert. + */ + byte[] tmp = alertQueue.removeData(2, 0); + short level = tmp[0]; + short description = tmp[1]; + + getPeer().notifyAlertReceived(level, description); + + if (level == AlertLevel.fatal) + { + /* + * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated + * without proper close_notify messages with level equal to warning. + */ + invalidateSession(); + + this.failedWithError = true; + this.closed = true; + + recordStream.safeClose(); + + throw new IOException(TLS_ERROR_MESSAGE); + } + else + { + + /* + * RFC 5246 7.2.1. The other party MUST respond with a close_notify alert of its own + * and close down the connection immediately, discarding any pending writes. + */ + // TODO Can close_notify be a fatal alert? + if (description == AlertDescription.close_notify) + { + handleClose(false); + } + + /* + * If it is just a warning, we continue. + */ + handleWarningMessage(description); + } + } + } + + /** + * This method is called, when a change cipher spec message is received. + * + * @throws IOException If the message has an invalid content or the handshake is not in the correct + * state. + */ + private void processChangeCipherSpec(byte[] buf, int off, int len) + throws IOException + { + for (int i = 0; i < len; ++i) + { + short message = TlsUtils.readUint8(buf, off + i); + + if (message != ChangeCipherSpec.change_cipher_spec) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + if (this.receivedChangeCipherSpec + || alertQueue.available() > 0 + || handshakeQueue.available() > 0) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + recordStream.receivedReadCipherSpec(); + + this.receivedChangeCipherSpec = true; + + handleChangeCipherSpecMessage(); + } + } + + public int applicationDataAvailable() + { + return applicationDataQueue.available(); + } + + /** + * Read data from the network. The method will return immediately, if there is still some data + * left in the buffer, or block until some application data has been read from the network. + * + * @param buf The buffer where the data will be copied to. + * @param offset The position where the data will be placed in the buffer. + * @param len The maximum number of bytes to read. + * @return The number of bytes read. + * @throws IOException If something goes wrong during reading data. + */ + public int readApplicationData(byte[] buf, int offset, int len) + throws IOException + { + if (len < 1) + { + return 0; + } + + while (applicationDataQueue.available() == 0) + { + /* + * We need to read some data. + */ + if (this.closed) + { + if (this.failedWithError) + { + /* + * Something went terribly wrong, we should throw an IOException + */ + throw new IOException(TLS_ERROR_MESSAGE); + } + + /* + * Connection has been closed, there is no more data to read. + */ + return -1; + } + if (!appDataReady) + { + throw new IllegalStateException("Cannot read application data until initial handshake completed."); + } + + safeReadRecord(); + } + + len = Math.min(len, applicationDataQueue.available()); + applicationDataQueue.removeData(buf, offset, len, 0); + return len; + } + + protected void safeReadRecord() + throws IOException + { + try + { + if (!recordStream.readRecord()) + { + // TODO It would be nicer to allow graceful connection close if between records +// this.failWithError(AlertLevel.warning, AlertDescription.close_notify); + throw new EOFException(); + } + } + catch (TlsFatalAlert e) + { + if (!closed) + { + this.failWithError(AlertLevel.fatal, e.getAlertDescription(), "Failed to read record", e); + } + throw e; + } + catch (IOException e) + { + if (!closed) + { + this.failWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to read record", e); + } + throw e; + } + catch (RuntimeException e) + { + if (!closed) + { + this.failWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to read record", e); + } + throw e; + } + } + + protected void safeWriteRecord(short type, byte[] buf, int offset, int len) + throws IOException + { + try + { + recordStream.writeRecord(type, buf, offset, len); + } + catch (TlsFatalAlert e) + { + if (!closed) + { + this.failWithError(AlertLevel.fatal, e.getAlertDescription(), "Failed to write record", e); + } + throw e; + } + catch (IOException e) + { + if (!closed) + { + this.failWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to write record", e); + } + throw e; + } + catch (RuntimeException e) + { + if (!closed) + { + this.failWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to write record", e); + } + throw e; + } + } + + /** + * Write some application data. Fragmentation is handled internally. Usable in both + * blocking/non-blocking modes.
      + *
      + * In blocking mode, the output will be automatically sent via the underlying transport. In + * non-blocking mode, call {@link #readOutput(byte[], int, int)} to get the output bytes to send + * to the peer.
      + *
      + * This method must not be called until after the initial handshake is complete. Attempting to + * call it earlier will result in an {@link IllegalStateException}. + * + * @param buf + * The buffer containing application data to send + * @param offset + * The offset at which the application data begins + * @param length + * The number of bytes of application data + * @throws IllegalStateException + * If called before the initial handshake has completed. + * @throws IOException + * If connection is already closed, or for encryption or transport errors. + */ + public void writeApplicationData(byte[] buf, int offset, int len) + throws IOException + { + if (this.closed) + { + if (this.failedWithError) + { + throw new IOException(TLS_ERROR_MESSAGE); + } + + throw new IOException("Sorry, connection has been closed, you cannot write more data"); + } + if (!appDataReady) + { + throw new IllegalStateException("Cannot write application data until initial handshake completed."); + } + + while (len > 0) + { + /* + * RFC 5246 6.2.1. Zero-length fragments of Application data MAY be sent as they are + * potentially useful as a traffic analysis countermeasure. + * + * NOTE: Actually, implementations appear to have settled on 1/n-1 record splitting. + */ + + if (this.appDataSplitEnabled) + { + /* + * Protect against known IV attack! + * + * DO NOT REMOVE THIS CODE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE. + */ + switch (appDataSplitMode) { + case ADS_MODE_0_N_FIRSTONLY: + this.appDataSplitEnabled = false; + // fall through intended! + case ADS_MODE_0_N: + safeWriteRecord(ContentType.application_data, TlsUtils.EMPTY_BYTES, 0, 0); + break; + case ADS_MODE_1_Nsub1: + default: + safeWriteRecord(ContentType.application_data, buf, offset, 1); + ++offset; + --len; + break; + } + } + + if (len > 0) + { + // Fragment data according to the current fragment limit. + int toWrite = Math.min(len, recordStream.getPlaintextLimit()); + safeWriteRecord(ContentType.application_data, buf, offset, toWrite); + offset += toWrite; + len -= toWrite; + } + } + } + + protected void setAppDataSplitMode(int appDataSplitMode) { + if (appDataSplitMode < ADS_MODE_1_Nsub1 || + appDataSplitMode > ADS_MODE_0_N_FIRSTONLY) + { + throw new IllegalArgumentException("Illegal appDataSplitMode mode: " + appDataSplitMode); + } + this.appDataSplitMode = appDataSplitMode; + } + + protected void writeHandshakeMessage(byte[] buf, int off, int len) throws IOException + { + while (len > 0) + { + // Fragment data according to the current fragment limit. + int toWrite = Math.min(len, recordStream.getPlaintextLimit()); + safeWriteRecord(ContentType.handshake, buf, off, toWrite); + off += toWrite; + len -= toWrite; + } + } + + /** + * @return An OutputStream which can be used to send data. Only allowed in blocking mode. + */ + public OutputStream getOutputStream() + { + if (!blocking) + { + throw new IllegalStateException("Cannot use OutputStream in non-blocking mode! Use offerOutput() instead."); + } + return this.tlsOutputStream; + } + + /** + * @return An InputStream which can be used to read data. Only allowed in blocking mode. + */ + public InputStream getInputStream() + { + if (!blocking) + { + throw new IllegalStateException("Cannot use InputStream in non-blocking mode! Use offerInput() instead."); + } + return this.tlsInputStream; + } + + /** + * Offer input from an arbitrary source. Only allowed in non-blocking mode.
      + *
      + * After this method returns, the input buffer is "owned" by this object. Other code + * must not attempt to do anything with it.
      + *
      + * This method will decrypt and process all records that are fully available. + * If only part of a record is available, the buffer will be retained until the + * remainder of the record is offered.
      + *
      + * If any records containing application data were processed, the decrypted data + * can be obtained using {@link #readInput(byte[], int, int)}. If any records + * containing protocol data were processed, a response may have been generated. + * You should always check to see if there is any available output after calling + * this method by calling {@link #getAvailableOutputBytes()}. + * @param input The input buffer to offer + * @throws IOException If an error occurs while decrypting or processing a record + */ + public void offerInput(byte[] input) throws IOException + { + if (blocking) + { + throw new IllegalStateException("Cannot use offerInput() in blocking mode! Use getInputStream() instead."); + } + + if (closed) + { + throw new IOException("Connection is closed, cannot accept any more input"); + } + + inputBuffers.addBytes(input); + + // loop while there are enough bytes to read the length of the next record + while (inputBuffers.available() >= RecordStream.TLS_HEADER_SIZE) + { + byte[] header = new byte[RecordStream.TLS_HEADER_SIZE]; + inputBuffers.peek(header); + + int totalLength = TlsUtils.readUint16(header, RecordStream.TLS_HEADER_LENGTH_OFFSET) + RecordStream.TLS_HEADER_SIZE; + if (inputBuffers.available() < totalLength) + { + // not enough bytes to read a whole record + break; + } + + safeReadRecord(); + } + } + + /** + * Gets the amount of received application data. A call to {@link #readInput(byte[], int, int)} + * is guaranteed to be able to return at least this much data.
      + *
      + * Only allowed in non-blocking mode. + * @return The number of bytes of available application data + */ + public int getAvailableInputBytes() + { + if (blocking) + { + throw new IllegalStateException("Cannot use getAvailableInputBytes() in blocking mode! Use getInputStream().available() instead."); + } + return applicationDataAvailable(); + } + + /** + * Retrieves received application data. Use {@link #getAvailableInputBytes()} to check + * how much application data is currently available. This method functions similarly to + * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data + * is available, nothing will be copied and zero will be returned.
      + *
      + * Only allowed in non-blocking mode. + * @param buffer The buffer to hold the application data + * @param offset The start offset in the buffer at which the data is written + * @param length The maximum number of bytes to read + * @return The total number of bytes copied to the buffer. May be less than the + * length specified if the length was greater than the amount of available data. + */ + public int readInput(byte[] buffer, int offset, int length) + { + if (blocking) + { + throw new IllegalStateException("Cannot use readInput() in blocking mode! Use getInputStream() instead."); + } + + length = Math.min(length, applicationDataQueue.available()); + if (length < 1) + { + return 0; + } + + applicationDataQueue.removeData(buffer, offset, length, 0); + return length; + } + + /** + * Gets the amount of encrypted data available to be sent. A call to + * {@link #readOutput(byte[], int, int)} is guaranteed to be able to return at + * least this much data.
      + *
      + * Only allowed in non-blocking mode. + * @return The number of bytes of available encrypted data + */ + public int getAvailableOutputBytes() + { + if (blocking) + { + throw new IllegalStateException("Cannot use getAvailableOutputBytes() in blocking mode! Use getOutputStream() instead."); + } + + return outputBuffer.getBuffer().available(); + } + + /** + * Retrieves encrypted data to be sent. Use {@link #getAvailableOutputBytes()} to check + * how much encrypted data is currently available. This method functions similarly to + * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data + * is available, nothing will be copied and zero will be returned.
      + *
      + * Only allowed in non-blocking mode. + * @param buffer The buffer to hold the encrypted data + * @param offset The start offset in the buffer at which the data is written + * @param length The maximum number of bytes to read + * @return The total number of bytes copied to the buffer. May be less than the + * length specified if the length was greater than the amount of available data. + */ + public int readOutput(byte[] buffer, int offset, int length) + { + if (blocking) + { + throw new IllegalStateException("Cannot use readOutput() in blocking mode! Use getOutputStream() instead."); + } + + int bytesToRead = Math.min(getAvailableOutputBytes(), length); + outputBuffer.getBuffer().removeData(buffer, offset, bytesToRead, 0); + return bytesToRead; + } + + /** + * Terminate this connection with an alert. Can be used for normal closure too. + * + * @param alertLevel + * See {@link AlertLevel} for values. + * @param alertDescription + * See {@link AlertDescription} for values. + * @throws IOException + * If alert was fatal. + */ + protected void failWithError(short alertLevel, short alertDescription, String message, Throwable cause) + throws IOException + { + /* + * Check if the connection is still open. + */ + if (!closed) + { + /* + * Prepare the message + */ + this.closed = true; + + if (alertLevel == AlertLevel.fatal) + { + /* + * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated + * without proper close_notify messages with level equal to warning. + */ + // TODO This isn't quite in the right place. Also, as of TLS 1.1 the above is obsolete. + invalidateSession(); + + this.failedWithError = true; + } + raiseAlert(alertLevel, alertDescription, message, cause); + recordStream.safeClose(); + if (alertLevel != AlertLevel.fatal) + { + return; + } + } + + throw new IOException(TLS_ERROR_MESSAGE); + } + + protected void invalidateSession() + { + if (this.sessionParameters != null) + { + this.sessionParameters.clear(); + this.sessionParameters = null; + } + + if (this.tlsSession != null) + { + this.tlsSession.invalidate(); + this.tlsSession = null; + } + } + + protected void processFinishedMessage(ByteArrayInputStream buf) + throws IOException + { + if (expected_verify_data == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + byte[] verify_data = TlsUtils.readFully(expected_verify_data.length, buf); + + assertEmpty(buf); + + /* + * Compare both checksums. + */ + if (!Arrays.constantTimeAreEqual(expected_verify_data, verify_data)) + { + /* + * Wrong checksum in the finished message. + */ + throw new TlsFatalAlert(AlertDescription.decrypt_error); + } + } + + protected void raiseAlert(short alertLevel, short alertDescription, String message, Throwable cause) + throws IOException + { + getPeer().notifyAlertRaised(alertLevel, alertDescription, message, cause); + + byte[] error = new byte[2]; + error[0] = (byte)alertLevel; + error[1] = (byte)alertDescription; + + safeWriteRecord(ContentType.alert, error, 0, 2); + } + + protected void raiseWarning(short alertDescription, String message) + throws IOException + { + raiseAlert(AlertLevel.warning, alertDescription, message, null); + } + + protected void sendCertificateMessage(Certificate certificate) + throws IOException + { + if (certificate == null) + { + certificate = Certificate.EMPTY_CHAIN; + } + + if (certificate.isEmpty()) + { + TlsContext context = getContext(); + if (!context.isServer()) + { + ProtocolVersion serverVersion = getContext().getServerVersion(); + if (serverVersion.isSSL()) + { + String errorMessage = serverVersion.toString() + " client didn't provide credentials"; + raiseWarning(AlertDescription.no_certificate, errorMessage); + return; + } + } + } + + HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate); + + certificate.encode(message); + + message.writeToRecordStream(); + + this.localCertificate = certificate; + } + + protected void sendChangeCipherSpecMessage() + throws IOException + { + byte[] message = new byte[]{ 1 }; + safeWriteRecord(ContentType.change_cipher_spec, message, 0, message.length); + recordStream.sentWriteCipherSpec(); + } + + protected void sendFinishedMessage() + throws IOException + { + byte[] verify_data = createVerifyData(getContext().isServer()); + + HandshakeMessage message = new HandshakeMessage(HandshakeType.finished, verify_data.length); + + message.write(verify_data); + + message.writeToRecordStream(); + } + + protected void sendSupplementalDataMessage(Vector supplementalData) + throws IOException + { + HandshakeMessage message = new HandshakeMessage(HandshakeType.supplemental_data); + + writeSupplementalData(message, supplementalData); + + message.writeToRecordStream(); + } + + protected byte[] createVerifyData(boolean isServer) + { + TlsContext context = getContext(); + String asciiLabel = isServer ? ExporterLabel.server_finished : ExporterLabel.client_finished; + byte[] sslSender = isServer ? TlsUtils.SSL_SERVER : TlsUtils.SSL_CLIENT; + byte[] hash = getCurrentPRFHash(context, recordStream.getHandshakeHash(), sslSender); + return TlsUtils.calculateVerifyData(context, asciiLabel, hash); + } + + /** + * Closes this connection. + * + * @throws IOException If something goes wrong during closing. + */ + public void close() + throws IOException + { + handleClose(true); + } + + protected void handleClose(boolean user_canceled) + throws IOException + { + if (!closed) + { + if (user_canceled && !appDataReady) + { + raiseWarning(AlertDescription.user_canceled, "User canceled handshake"); + } + this.failWithError(AlertLevel.warning, AlertDescription.close_notify, "Connection closed", null); + } + } + + public void flush() + throws IOException + { + recordStream.flush(); + } + + public boolean isClosed() + { + return closed; + } + + protected short processMaxFragmentLengthExtension(Hashtable clientExtensions, Hashtable serverExtensions, + short alertDescription) + throws IOException + { + short maxFragmentLength = TlsExtensionsUtils.getMaxFragmentLengthExtension(serverExtensions); + if (maxFragmentLength >= 0) + { + if (!MaxFragmentLength.isValid(maxFragmentLength) + || (!this.resumedSession && maxFragmentLength != TlsExtensionsUtils + .getMaxFragmentLengthExtension(clientExtensions))) + { + throw new TlsFatalAlert(alertDescription); + } + } + return maxFragmentLength; + } + + protected void refuseRenegotiation() throws IOException + { + /* + * RFC 5746 4.5 SSLv3 clients that refuse renegotiation SHOULD use a fatal + * handshake_failure alert. + */ + if (TlsUtils.isSSL(getContext())) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + raiseWarning(AlertDescription.no_renegotiation, "Renegotiation not supported"); + } + + /** + * Make sure the InputStream 'buf' now empty. Fail otherwise. + * + * @param buf The InputStream to check. + * @throws IOException If 'buf' is not empty. + */ + protected static void assertEmpty(ByteArrayInputStream buf) + throws IOException + { + if (buf.available() > 0) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + } + + protected static byte[] createRandomBlock(boolean useGMTUnixTime, TlsContext context) + { + byte[] result = context.getCrypto().createNonce(32); + + if (useGMTUnixTime) + { + TlsUtils.writeGMTUnixTime(result, 0); + } + + return result; + } + + protected static byte[] createRenegotiationInfo(byte[] renegotiated_connection) + throws IOException + { + return TlsUtils.encodeOpaque8(renegotiated_connection); + } + + protected static void establishMasterSecret(TlsContext context, TlsKeyExchange keyExchange) + throws IOException + { + TlsSecret preMasterSecret = keyExchange.generatePreMasterSecret(); + if (preMasterSecret == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + try + { + context.getSecurityParameters().masterSecret = TlsUtils.calculateMasterSecret(context, preMasterSecret); + } + finally + { + /* + * RFC 2246 8.1. The pre_master_secret should be deleted from memory once the + * master_secret has been computed. + */ + preMasterSecret.destroy(); + } + } + + /** + * 'sender' only relevant to SSLv3 + */ + protected static byte[] getCurrentPRFHash(TlsContext context, TlsHandshakeHash handshakeHash, byte[] sslSender) + { + TlsHash d = handshakeHash.forkPRFHash(); + + if (sslSender != null && TlsUtils.isSSL(context)) + { + d.update(sslSender, 0, sslSender.length); + } + + return d.calculateHash(); + } + + protected static Hashtable readExtensions(ByteArrayInputStream input) + throws IOException + { + if (input.available() < 1) + { + return null; + } + + byte[] extBytes = TlsUtils.readOpaque16(input); + + assertEmpty(input); + + ByteArrayInputStream buf = new ByteArrayInputStream(extBytes); + + // Integer -> byte[] + Hashtable extensions = new Hashtable(); + + while (buf.available() > 0) + { + Integer extension_type = Integers.valueOf(TlsUtils.readUint16(buf)); + byte[] extension_data = TlsUtils.readOpaque16(buf); + + /* + * RFC 3546 2.3 There MUST NOT be more than one extension of the same type. + */ + if (null != extensions.put(extension_type, extension_data)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + + return extensions; + } + + protected static Vector readSupplementalDataMessage(ByteArrayInputStream input) + throws IOException + { + byte[] supp_data = TlsUtils.readOpaque24(input); + + assertEmpty(input); + + ByteArrayInputStream buf = new ByteArrayInputStream(supp_data); + + Vector supplementalData = new Vector(); + + while (buf.available() > 0) + { + int supp_data_type = TlsUtils.readUint16(buf); + byte[] data = TlsUtils.readOpaque16(buf); + + supplementalData.addElement(new SupplementalDataEntry(supp_data_type, data)); + } + + return supplementalData; + } + + protected static TlsCredentials validateCredentials(TlsCredentials credentials) + throws IOException + { + if (credentials != null) + { + int count = 0; + count += (credentials instanceof TlsCredentialedAgreement) ? 1 : 0; + count += (credentials instanceof TlsCredentialedDecryptor) ? 1 : 0; + count += (credentials instanceof TlsCredentialedSigner) ? 1 : 0; + if (count != 1) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + return credentials; + } + + protected static void writeExtensions(OutputStream output, Hashtable extensions) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + /* + * NOTE: There are reports of servers that don't accept a zero-length extension as the last + * one, so we write out any zero-length ones first as a best-effort workaround. + */ + writeSelectedExtensions(buf, extensions, true); + writeSelectedExtensions(buf, extensions, false); + + byte[] extBytes = buf.toByteArray(); + + TlsUtils.writeOpaque16(extBytes, output); + } + + protected static void writeSelectedExtensions(OutputStream output, Hashtable extensions, boolean selectEmpty) + throws IOException + { + Enumeration keys = extensions.keys(); + while (keys.hasMoreElements()) + { + Integer key = (Integer)keys.nextElement(); + int extension_type = key.intValue(); + byte[] extension_data = (byte[])extensions.get(key); + + if (selectEmpty == (extension_data.length == 0)) + { + TlsUtils.checkUint16(extension_type); + TlsUtils.writeUint16(extension_type, output); + TlsUtils.writeOpaque16(extension_data, output); + } + } + } + + protected static void writeSupplementalData(OutputStream output, Vector supplementalData) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + for (int i = 0; i < supplementalData.size(); ++i) + { + SupplementalDataEntry entry = (SupplementalDataEntry)supplementalData.elementAt(i); + + int supp_data_type = entry.getDataType(); + TlsUtils.checkUint16(supp_data_type); + TlsUtils.writeUint16(supp_data_type, buf); + TlsUtils.writeOpaque16(entry.getData(), buf); + } + + byte[] supp_data = buf.toByteArray(); + + TlsUtils.writeOpaque24(supp_data, output); + } + + protected static int getPRFAlgorithm(TlsContext context, int cipherSuite) throws IOException + { + boolean isTLSv12 = TlsUtils.isTLSv12(context); + + switch (cipherSuite) + { + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM: + case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8: + case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: + case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB: + case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8: + case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_128_CCM: + case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB: + case CipherSuite.TLS_PSK_WITH_AES_256_CCM: + case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8: + case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_128_CCM: + case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_256_CCM: + case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_NULL_SHA256: + { + if (isTLSv12) + { + return PRFAlgorithm.tls_prf_sha256; + } + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_8_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: + { + if (isTLSv12) + { + return PRFAlgorithm.tls_prf_sha384; + } + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384: + { + if (isTLSv12) + { + return PRFAlgorithm.tls_prf_sha384; + } + return PRFAlgorithm.tls_prf_legacy; + } + + default: + { + if (isTLSv12) + { + return PRFAlgorithm.tls_prf_sha256; + } + return PRFAlgorithm.tls_prf_legacy; + } + } + } + + class HandshakeMessage extends ByteArrayOutputStream + { + HandshakeMessage(short handshakeType) throws IOException + { + this(handshakeType, 60); + } + + HandshakeMessage(short handshakeType, int length) throws IOException + { + super(length + 4); + TlsUtils.writeUint8(handshakeType, this); + // Reserve space for length + count += 3; + } + + void writeToRecordStream() throws IOException + { + // Patch actual length back in + int length = count - 4; + TlsUtils.checkUint24(length); + TlsUtils.writeUint24(length, buf, 1); + writeHandshakeMessage(buf, 0, count); + buf = null; + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsPSKIdentity.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsPSKIdentity.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsPSKIdentity.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsPSKIdentity.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,12 @@ +package org.bouncycastle.tls; + +public interface TlsPSKIdentity +{ + void skipIdentityHint(); + + void notifyIdentityHint(byte[] psk_identity_hint); + + byte[] getPSKIdentity(); + + byte[] getPSK(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsPSKIdentityManager.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsPSKIdentityManager.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsPSKIdentityManager.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsPSKIdentityManager.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,8 @@ +package org.bouncycastle.tls; + +public interface TlsPSKIdentityManager +{ + byte[] getHint(); + + byte[] getPSK(byte[] identity); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsPSKKeyExchange.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsPSKKeyExchange.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsPSKKeyExchange.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsPSKKeyExchange.java 2016-11-01 20:33:01.000000000 +0000 @@ -0,0 +1,367 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsAgreement; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsDHConfig; +import org.bouncycastle.tls.crypto.TlsECConfig; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.io.Streams; + +/** + * (D)TLS PSK key exchange (RFC 4279). + */ +public class TlsPSKKeyExchange + extends AbstractTlsKeyExchange +{ + protected TlsPSKIdentity pskIdentity; + protected TlsPSKIdentityManager pskIdentityManager; + protected TlsDHConfigVerifier dhConfigVerifier; + protected TlsECConfigVerifier ecConfigVerifier; + protected short[] clientECPointFormats, serverECPointFormats; + + protected byte[] psk_identity_hint = null; + protected byte[] psk = null; + + protected TlsDHConfig dhConfig; + protected TlsECConfig ecConfig; + protected TlsAgreement agreement; + + protected TlsCredentialedDecryptor serverCredentials = null; + protected TlsCertificate serverCertificate; + protected TlsSecret preMasterSecret; + + public TlsPSKKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsPSKIdentity pskIdentity, + TlsDHConfigVerifier dhConfigVerifier, TlsECConfigVerifier ecConfigVerifier, short[] clientECPointFormats, + short[] serverECPointFormats) + { + this(keyExchange, supportedSignatureAlgorithms, pskIdentity, null, dhConfigVerifier, null, ecConfigVerifier, + null, clientECPointFormats, serverECPointFormats); + } + + public TlsPSKKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsPSKIdentity pskIdentity, + TlsPSKIdentityManager pskIdentityManager, TlsDHConfig dhConfig, TlsECConfig ecConfig, + short[] serverECPointFormats) + { + this(keyExchange, supportedSignatureAlgorithms, pskIdentity, pskIdentityManager, null, dhConfig, null, ecConfig, + null, serverECPointFormats); + } + + private TlsPSKKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsPSKIdentity pskIdentity, + TlsPSKIdentityManager pskIdentityManager, TlsDHConfigVerifier dhConfigVerifier, TlsDHConfig dhConfig, + TlsECConfigVerifier ecConfigVerifier, TlsECConfig ecConfig, short[] clientECPointFormats, + short[] serverECPointFormats) + { + super(keyExchange, supportedSignatureAlgorithms); + + switch (keyExchange) + { + case KeyExchangeAlgorithm.DHE_PSK: + case KeyExchangeAlgorithm.ECDHE_PSK: + case KeyExchangeAlgorithm.PSK: + case KeyExchangeAlgorithm.RSA_PSK: + break; + default: + throw new IllegalArgumentException("unsupported key exchange algorithm"); + } + + this.pskIdentity = pskIdentity; + this.pskIdentityManager = pskIdentityManager; + this.dhConfigVerifier = dhConfigVerifier; + this.dhConfig = dhConfig; + this.ecConfigVerifier = ecConfigVerifier; + this.ecConfig = ecConfig; + this.clientECPointFormats = clientECPointFormats; + this.serverECPointFormats = serverECPointFormats; + } + + public void skipServerCredentials() throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.RSA_PSK) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public void processServerCredentials(TlsCredentials serverCredentials) throws IOException + { + if (keyExchange != KeyExchangeAlgorithm.RSA_PSK) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + if (!(serverCredentials instanceof TlsCredentialedDecryptor)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.serverCredentials = (TlsCredentialedDecryptor)serverCredentials; + } + + public void processServerCertificate(Certificate serverCertificate) throws IOException + { + if (keyExchange != KeyExchangeAlgorithm.RSA_PSK) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + if (serverCertificate.isEmpty()) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + checkServerCertSigAlg(serverCertificate); + + this.serverCertificate = serverCertificate.getCertificateAt(0).useInRole(ConnectionEnd.server, keyExchange); + } + + public byte[] generateServerKeyExchange() throws IOException + { + this.psk_identity_hint = pskIdentityManager.getHint(); + + if (this.psk_identity_hint == null && !requiresServerKeyExchange()) + { + return null; + } + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + if (this.psk_identity_hint == null) + { + TlsUtils.writeOpaque16(TlsUtils.EMPTY_BYTES, buf); + } + else + { + TlsUtils.writeOpaque16(this.psk_identity_hint, buf); + } + + if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) + { + if (this.dhConfig == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + TlsDHUtils.writeDHConfig(dhConfig, buf); + + this.agreement = context.getCrypto().createDHDomain(dhConfig).createDH(); + + generateEphemeralDH(buf); + } + else if (this.keyExchange == KeyExchangeAlgorithm.ECDHE_PSK) + { + if (this.ecConfig == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + TlsECCUtils.writeECConfig(ecConfig, buf); + + this.agreement = context.getCrypto().createECDomain(ecConfig).createECDH(); + + generateEphemeralECDH(buf); + } + + return buf.toByteArray(); + } + + public boolean requiresServerKeyExchange() + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.DHE_PSK: + case KeyExchangeAlgorithm.ECDHE_PSK: + return true; + default: + return false; + } + } + + public void processServerKeyExchange(InputStream input) throws IOException + { + this.psk_identity_hint = TlsUtils.readOpaque16(input); + + if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) + { + this.dhConfig = TlsDHUtils.receiveDHConfig(dhConfigVerifier, input); + + byte[] y = TlsUtils.readOpaque16(input); + + this.agreement = context.getCrypto().createDHDomain(dhConfig).createDH(); + + processEphemeralDH(y); + } + else if (this.keyExchange == KeyExchangeAlgorithm.ECDHE_PSK) + { + this.ecConfig = TlsECCUtils.receiveECConfig(ecConfigVerifier, serverECPointFormats, input); + + byte[] point = TlsUtils.readOpaque8(input); + + this.agreement = context.getCrypto().createECDomain(ecConfig).createECDH(); + + processEphemeralECDH(clientECPointFormats, point); + } + } + + public void validateCertificateRequest(CertificateRequest certificateRequest) throws IOException + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public void processClientCredentials(TlsCredentials clientCredentials) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public void generateClientKeyExchange(OutputStream output) throws IOException + { + if (psk_identity_hint == null) + { + pskIdentity.skipIdentityHint(); + } + else + { + pskIdentity.notifyIdentityHint(psk_identity_hint); + } + + byte[] psk_identity = pskIdentity.getPSKIdentity(); + if (psk_identity == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.psk = pskIdentity.getPSK(); + if (psk == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + TlsUtils.writeOpaque16(psk_identity, output); + + context.getSecurityParameters().pskIdentity = Arrays.clone(psk_identity); + + if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) + { + generateEphemeralDH(output); + } + else if (this.keyExchange == KeyExchangeAlgorithm.ECDHE_PSK) + { + generateEphemeralECDH(output); + } + else if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK) + { + this.preMasterSecret = TlsRSAUtils.generateEncryptedPreMasterSecret(context, serverCertificate, output); + } + } + + public void processClientKeyExchange(InputStream input) throws IOException + { + byte[] psk_identity = TlsUtils.readOpaque16(input); + + this.psk = pskIdentityManager.getPSK(psk_identity); + if (psk == null) + { + throw new TlsFatalAlert(AlertDescription.unknown_psk_identity); + } + + context.getSecurityParameters().pskIdentity = psk_identity; + + if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) + { + byte[] y = TlsUtils.readOpaque16(input); + + processEphemeralDH(y); + } + else if (this.keyExchange == KeyExchangeAlgorithm.ECDHE_PSK) + { + byte[] point = TlsUtils.readOpaque8(input); + + processEphemeralECDH(serverECPointFormats, point); + } + else if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK) + { + byte[] encryptedPreMasterSecret; + if (TlsUtils.isSSL(context)) + { + // TODO Do any SSLv3 clients actually include the length? + encryptedPreMasterSecret = Streams.readAll(input); + } + else + { + encryptedPreMasterSecret = TlsUtils.readOpaque16(input); + } + + this.preMasterSecret = serverCredentials.decrypt(new TlsCryptoParameters(context), encryptedPreMasterSecret); + } + } + + public TlsSecret generatePreMasterSecret() throws IOException + { + byte[] other_secret = generateOtherSecret(psk.length); + + ByteArrayOutputStream buf = new ByteArrayOutputStream(4 + other_secret.length + psk.length); + TlsUtils.writeOpaque16(other_secret, buf); + TlsUtils.writeOpaque16(psk, buf); + + Arrays.fill(psk, (byte)0); + this.psk = null; + + return context.getCrypto().createSecret(buf.toByteArray()); + } + + protected void generateEphemeralDH(OutputStream output) throws IOException + { + byte[] y = agreement.generateEphemeral(); + TlsUtils.writeOpaque16(y, output); + } + + protected void generateEphemeralECDH(OutputStream output) throws IOException + { + byte[] point = agreement.generateEphemeral(); + TlsUtils.writeOpaque8(point, output); + } + + protected byte[] generateOtherSecret(int pskLength) throws IOException + { + if (this.keyExchange == KeyExchangeAlgorithm.PSK) + { + return new byte[pskLength]; + } + + if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK + || this.keyExchange == KeyExchangeAlgorithm.ECDHE_PSK) + { + if (agreement != null) + { + return agreement.calculateSecret().extract(); + } + } + + if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK) + { + if (preMasterSecret != null) + { + return this.preMasterSecret.extract(); + } + } + + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + protected void processEphemeralDH(byte[] y) throws IOException + { + this.agreement.receivePeerValue(y); + } + + protected void processEphemeralECDH(short[] localECPointFormats, byte[] point) throws IOException + { + TlsECCUtils.checkPointEncoding(localECPointFormats, ecConfig.getNamedCurve(), point); + + this.agreement.receivePeerValue(point); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsRSAKeyExchange.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsRSAKeyExchange.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsRSAKeyExchange.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsRSAKeyExchange.java 2016-11-01 20:33:01.000000000 +0000 @@ -0,0 +1,115 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.io.Streams; + +/** + * (D)TLS and SSLv3 RSA key exchange. + */ +public class TlsRSAKeyExchange + extends AbstractTlsKeyExchange +{ + protected TlsCredentialedDecryptor serverCredentials = null; + protected TlsCertificate serverCertificate; + protected TlsSecret preMasterSecret; + + public TlsRSAKeyExchange(Vector supportedSignatureAlgorithms) + { + super(KeyExchangeAlgorithm.RSA, supportedSignatureAlgorithms); + } + + public void skipServerCredentials() + throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public void processServerCredentials(TlsCredentials serverCredentials) + throws IOException + { + if (!(serverCredentials instanceof TlsCredentialedDecryptor)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.serverCredentials = (TlsCredentialedDecryptor)serverCredentials; + } + + public void processServerCertificate(Certificate serverCertificate) + throws IOException + { + if (serverCertificate.isEmpty()) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + checkServerCertSigAlg(serverCertificate); + + this.serverCertificate = serverCertificate.getCertificateAt(0).useInRole(ConnectionEnd.server, keyExchange); + } + + public void validateCertificateRequest(CertificateRequest certificateRequest) + throws IOException + { + short[] types = certificateRequest.getCertificateTypes(); + for (int i = 0; i < types.length; ++i) + { + switch (types[i]) + { + case ClientCertificateType.rsa_sign: + case ClientCertificateType.dss_sign: + case ClientCertificateType.ecdsa_sign: + break; + default: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + } + } + + public void processClientCredentials(TlsCredentials clientCredentials) + throws IOException + { + if (!(clientCredentials instanceof TlsCredentialedSigner)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public void generateClientKeyExchange(OutputStream output) + throws IOException + { + this.preMasterSecret = TlsRSAUtils.generateEncryptedPreMasterSecret(context, serverCertificate, output); + } + + public void processClientKeyExchange(InputStream input) + throws IOException + { + byte[] encryptedPreMasterSecret; + if (TlsUtils.isSSL(context)) + { + // TODO Do any SSLv3 clients actually include the length? + encryptedPreMasterSecret = Streams.readAll(input); + } + else + { + encryptedPreMasterSecret = TlsUtils.readOpaque16(input); + } + + this.preMasterSecret = serverCredentials.decrypt(new TlsCryptoParameters(context), encryptedPreMasterSecret); + } + + public TlsSecret generatePreMasterSecret() + throws IOException + { + TlsSecret tmp = this.preMasterSecret; + this.preMasterSecret = null; + return tmp; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsRSAUtils.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsRSAUtils.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsRSAUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsRSAUtils.java 2016-10-08 00:27:24.000000000 +0000 @@ -0,0 +1,40 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.OutputStream; + +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsSecret; + +/** + * RSA Utility methods. + */ +public abstract class TlsRSAUtils +{ + private TlsRSAUtils() + { + } + + /* + * Generate a pre_master_secret and send it encrypted to the server + */ + public static TlsSecret generateEncryptedPreMasterSecret(TlsContext context, TlsCertificate certificate, + OutputStream output) throws IOException + { + TlsSecret preMasterSecret = context.getCrypto().generateRSAPreMasterSecret(context.getClientVersion()); + + byte[] encryptedPreMasterSecret = preMasterSecret.encrypt(certificate); + + if (TlsUtils.isSSL(context)) + { + // TODO Do any SSLv3 servers actually expect the length? + output.write(encryptedPreMasterSecret); + } + else + { + TlsUtils.writeOpaque16(encryptedPreMasterSecret, output); + } + + return preMasterSecret; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsServerContextImpl.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsServerContextImpl.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsServerContextImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsServerContextImpl.java 2016-10-04 08:38:15.000000000 +0000 @@ -0,0 +1,18 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsCrypto; + +class TlsServerContextImpl + extends AbstractTlsContext + implements TlsServerContext +{ + TlsServerContextImpl(TlsCrypto crypto, SecurityParameters securityParameters) + { + super(crypto, securityParameters); + } + + public boolean isServer() + { + return true; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsServerContext.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsServerContext.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsServerContext.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsServerContext.java 2016-11-22 03:46:01.000000000 +0000 @@ -0,0 +1,9 @@ +package org.bouncycastle.tls; + +/** + * Marker interface to distinguish a TLS server context. + */ +public interface TlsServerContext + extends TlsContext +{ +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsServer.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsServer.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsServer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsServer.java 2016-11-22 03:46:01.000000000 +0000 @@ -0,0 +1,108 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedAgreement; +import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedDecryptor; + +/** + * Interface describing a TLS server endpoint. + */ +public interface TlsServer + extends TlsPeer +{ + void init(TlsServerContext context); + + void notifyClientVersion(ProtocolVersion clientVersion) throws IOException; + + void notifyFallback(boolean isFallback) throws IOException; + + void notifyOfferedCipherSuites(int[] offeredCipherSuites) + throws IOException; + + void notifyOfferedCompressionMethods(short[] offeredCompressionMethods) + throws IOException; + + // Hashtable is (Integer -> byte[]) + void processClientExtensions(Hashtable clientExtensions) + throws IOException; + + ProtocolVersion getServerVersion() + throws IOException; + + int getSelectedCipherSuite() + throws IOException; + + short getSelectedCompressionMethod() + throws IOException; + + // Hashtable is (Integer -> byte[]) + Hashtable getServerExtensions() + throws IOException; + + // Vector is (SupplementalDataEntry) + Vector getServerSupplementalData() + throws IOException; + + /** + * Return server credentials to use. The returned value may be null, or else it MUST implement + * exactly one of {@link TlsCredentialedAgreement}, {@link TlsCredentialedDecryptor}, or + * {@link TlsCredentialedSigner}, depending on the key exchange that was negotiated. + * + * @see {@link BcDefaultTlsCredentialedAgreement}, {@link BcDefaultTlsCredentialedDecryptor}, + * {@link DefaultTlsCredentialedSigner} + * @return a TlsCredentials object or null for anonymous key exchanges + * @throws IOException + */ + TlsCredentials getCredentials() + throws IOException; + + /** + * This method will be called (only) if the server included an extension of type + * "status_request" with empty "extension_data" in the extended server hello. See RFC 3546 + * 3.6. Certificate Status Request. If a non-null {@link CertificateStatus} is returned, it + * is sent to the client as a handshake message of type "certificate_status". + * + * @return A {@link CertificateStatus} to be sent to the client (or null for none). + * @throws IOException + */ + CertificateStatus getCertificateStatus() + throws IOException; + + TlsKeyExchange getKeyExchange() + throws IOException; + + CertificateRequest getCertificateRequest() + throws IOException; + + // Vector is (SupplementalDataEntry) + void processClientSupplementalData(Vector clientSupplementalData) + throws IOException; + + /** + * Called by the protocol handler to report the client certificate, only if + * {@link #getCertificateRequest()} returned non-null. + * + * Note: this method is responsible for certificate verification and validation. + * + * @param clientCertificate + * the effective client certificate (may be an empty chain). + * @throws IOException + */ + void notifyClientCertificate(Certificate clientCertificate) + throws IOException; + + /** + * RFC 5077 3.3. NewSessionTicket Handshake Message. + *

      + * This method will be called (only) if a NewSessionTicket extension was sent by the server. See + * RFC 5077 4. Recommended Ticket Construction for recommended format and protection. + * + * @return The ticket. + * @throws IOException + */ + NewSessionTicket getNewSessionTicket() + throws IOException; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java 2016-11-21 00:46:11.000000000 +0000 @@ -0,0 +1,860 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsVerifier; +import org.bouncycastle.util.Arrays; + +public class TlsServerProtocol + extends TlsProtocol +{ + protected TlsServer tlsServer = null; + TlsServerContextImpl tlsServerContext = null; + + protected TlsKeyExchange keyExchange = null; + protected TlsCredentials serverCredentials = null; + protected CertificateRequest certificateRequest = null; + + protected short clientCertificateType = -1; + protected TlsHandshakeHash prepareFinishHash = null; + + /** + * Constructor for non-blocking mode.
      + *
      + * When data is received, use {@link #offerOutput(byte[], int, int)} to + * provide the received ciphertext, then use + * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.
      + *
      + * Similarly, when data needs to be sent, use + * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use + * {@link #readOutput(byte[], int, int)} to get the corresponding + * ciphertext. fetch + */ + public TlsServerProtocol() + { + super(); + } + + /** + * Constructor for blocking mode. + * @param input The stream of data from the client + * @param output The stream of data to the client + */ + public TlsServerProtocol(InputStream input, OutputStream output) + { + super(input, output); + } + + /** + * Receives a TLS handshake in the role of server.
      + *
      + * In blocking mode, this will not return until the handshake is complete. + * In non-blocking mode, use {@link TlsPeer#notifyHandshakeComplete()} to + * receive a callback when the handshake is complete. + * + * @param tlsServer + * @throws IOException If in blocking mode and handshake was not successful. + */ + public void accept(TlsServer tlsServer) + throws IOException + { + if (tlsServer == null) + { + throw new IllegalArgumentException("'tlsServer' cannot be null"); + } + if (this.tlsServer != null) + { + throw new IllegalStateException("'accept' can only be called once"); + } + + this.tlsServer = tlsServer; + + this.securityParameters = new SecurityParameters(); + this.securityParameters.entity = ConnectionEnd.server; + + this.tlsServerContext = new TlsServerContextImpl(tlsServer.getCrypto(), securityParameters); + + this.securityParameters.serverRandom = createRandomBlock(tlsServer.shouldUseGMTUnixTime(), tlsServerContext); + + this.tlsServer.init(tlsServerContext); + this.recordStream.init(tlsServerContext); + + this.recordStream.setRestrictReadVersion(false); + + blockForHandshake(); + } + + protected void cleanupHandshake() + { + super.cleanupHandshake(); + + this.keyExchange = null; + this.serverCredentials = null; + this.certificateRequest = null; + this.prepareFinishHash = null; + } + + protected TlsContext getContext() + { + return tlsServerContext; + } + + AbstractTlsContext getContextAdmin() + { + return tlsServerContext; + } + + protected TlsPeer getPeer() + { + return tlsServer; + } + + protected void handleHandshakeMessage(short type, byte[] data) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(data); + + switch (type) + { + case HandshakeType.client_hello: + { + switch (this.connection_state) + { + case CS_START: + { + receiveClientHelloMessage(buf); + this.connection_state = CS_CLIENT_HELLO; + + // NOTE: Currently no server support for session resumption + { + invalidateSession(); + + this.tlsSession = TlsUtils.importSession(TlsUtils.EMPTY_BYTES, null); + this.sessionParameters = null; + } + + sendServerHelloMessage(); + this.connection_state = CS_SERVER_HELLO; + + recordStream.notifyHelloComplete(); + + Vector serverSupplementalData = tlsServer.getServerSupplementalData(); + if (serverSupplementalData != null) + { + sendSupplementalDataMessage(serverSupplementalData); + } + this.connection_state = CS_SERVER_SUPPLEMENTAL_DATA; + + this.keyExchange = tlsServer.getKeyExchange(); + this.keyExchange.init(getContext()); + + this.serverCredentials = validateCredentials(tlsServer.getCredentials()); + + Certificate serverCertificate = null; + + if (this.serverCredentials == null) + { + this.keyExchange.skipServerCredentials(); + } + else + { + this.keyExchange.processServerCredentials(this.serverCredentials); + + serverCertificate = this.serverCredentials.getCertificate(); + sendCertificateMessage(serverCertificate); + } + this.connection_state = CS_SERVER_CERTIFICATE; + + // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus + if (serverCertificate == null || serverCertificate.isEmpty()) + { + this.allowCertificateStatus = false; + } + + if (this.allowCertificateStatus) + { + CertificateStatus certificateStatus = tlsServer.getCertificateStatus(); + if (certificateStatus != null) + { + sendCertificateStatusMessage(certificateStatus); + } + } + + this.connection_state = CS_CERTIFICATE_STATUS; + + byte[] serverKeyExchange = this.keyExchange.generateServerKeyExchange(); + if (serverKeyExchange != null) + { + sendServerKeyExchangeMessage(serverKeyExchange); + } + this.connection_state = CS_SERVER_KEY_EXCHANGE; + + if (this.serverCredentials != null) + { + this.certificateRequest = tlsServer.getCertificateRequest(); + if (this.certificateRequest != null) + { + if (TlsUtils.isTLSv12(getContext()) != (certificateRequest.getSupportedSignatureAlgorithms() != null)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.keyExchange.validateCertificateRequest(certificateRequest); + + sendCertificateRequestMessage(certificateRequest); + + TlsUtils.trackHashAlgorithms(this.recordStream.getHandshakeHash(), + this.certificateRequest.getSupportedSignatureAlgorithms()); + } + } + this.connection_state = CS_CERTIFICATE_REQUEST; + + sendServerHelloDoneMessage(); + this.connection_state = CS_SERVER_HELLO_DONE; + + this.recordStream.getHandshakeHash().sealHashAlgorithms(); + + break; + } + case CS_END: + { + refuseRenegotiation(); + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + break; + } + case HandshakeType.supplemental_data: + { + switch (this.connection_state) + { + case CS_SERVER_HELLO_DONE: + { + tlsServer.processClientSupplementalData(readSupplementalDataMessage(buf)); + this.connection_state = CS_CLIENT_SUPPLEMENTAL_DATA; + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + break; + } + case HandshakeType.certificate: + { + switch (this.connection_state) + { + case CS_SERVER_HELLO_DONE: + { + tlsServer.processClientSupplementalData(null); + // NB: Fall through to next case label + } + case CS_CLIENT_SUPPLEMENTAL_DATA: + { + if (this.certificateRequest == null) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + receiveCertificateMessage(buf); + this.connection_state = CS_CLIENT_CERTIFICATE; + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + break; + } + case HandshakeType.client_key_exchange: + { + switch (this.connection_state) + { + case CS_SERVER_HELLO_DONE: + { + tlsServer.processClientSupplementalData(null); + // NB: Fall through to next case label + } + case CS_CLIENT_SUPPLEMENTAL_DATA: + { + if (this.certificateRequest == null) + { + this.keyExchange.skipClientCredentials(); + } + else + { + if (TlsUtils.isTLSv12(getContext())) + { + /* + * RFC 5246 If no suitable certificate is available, the client MUST send a + * certificate message containing no certificates. + * + * NOTE: In previous RFCs, this was SHOULD instead of MUST. + */ + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + else if (TlsUtils.isSSL(getContext())) + { + if (this.peerCertificate == null) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + } + else + { + notifyClientCertificate(Certificate.EMPTY_CHAIN); + } + } + // NB: Fall through to next case label + } + case CS_CLIENT_CERTIFICATE: + { + receiveClientKeyExchangeMessage(buf); + this.connection_state = CS_CLIENT_KEY_EXCHANGE; + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + break; + } + case HandshakeType.certificate_verify: + { + switch (this.connection_state) + { + case CS_CLIENT_KEY_EXCHANGE: + { + /* + * RFC 5246 7.4.8 This message is only sent following a client certificate that has + * signing capability (i.e., all certificates except those containing fixed + * Diffie-Hellman parameters). + */ + if (!expectCertificateVerifyMessage()) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + receiveCertificateVerifyMessage(buf); + this.connection_state = CS_CERTIFICATE_VERIFY; + + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + break; + } + case HandshakeType.finished: + { + switch (this.connection_state) + { + case CS_CLIENT_KEY_EXCHANGE: + { + if (expectCertificateVerifyMessage()) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + // NB: Fall through to next case label + } + case CS_CERTIFICATE_VERIFY: + { + processFinishedMessage(buf); + this.connection_state = CS_CLIENT_FINISHED; + + if (this.expectSessionTicket) + { + sendNewSessionTicketMessage(tlsServer.getNewSessionTicket()); + sendChangeCipherSpecMessage(); + } + this.connection_state = CS_SERVER_SESSION_TICKET; + + sendFinishedMessage(); + this.connection_state = CS_SERVER_FINISHED; + this.connection_state = CS_END; + + completeHandshake(); + break; + } + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + break; + } + case HandshakeType.hello_request: + case HandshakeType.hello_verify_request: + case HandshakeType.server_hello: + case HandshakeType.server_key_exchange: + case HandshakeType.certificate_request: + case HandshakeType.server_hello_done: + case HandshakeType.session_ticket: + default: + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + } + + protected void handleWarningMessage(short description) + throws IOException + { + switch (description) + { + case AlertDescription.no_certificate: + { + /* + * SSL 3.0 If the server has sent a certificate request Message, the client must send + * either the certificate message or a no_certificate alert. + */ + if (TlsUtils.isSSL(getContext()) && certificateRequest != null) + { + notifyClientCertificate(Certificate.EMPTY_CHAIN); + } + break; + } + default: + { + super.handleWarningMessage(description); + break; + } + } + } + + protected void notifyClientCertificate(Certificate clientCertificate) + throws IOException + { + if (certificateRequest == null) + { + throw new IllegalStateException(); + } + + if (peerCertificate != null) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + this.peerCertificate = clientCertificate; + + if (clientCertificate.isEmpty()) + { + this.keyExchange.skipClientCredentials(); + } + else + { + + /* + * TODO RFC 5246 7.4.6. If the certificate_authorities list in the certificate request + * message was non-empty, one of the certificates in the certificate chain SHOULD be + * issued by one of the listed CAs. + */ + + this.clientCertificateType = TlsUtils.getClientCertificateType(getContext(), clientCertificate, + this.serverCredentials.getCertificate()); + + this.keyExchange.processClientCertificate(clientCertificate); + } + + /* + * RFC 5246 7.4.6. If the client does not send any certificates, the server MAY at its + * discretion either continue the handshake without client authentication, or respond with a + * fatal handshake_failure alert. Also, if some aspect of the certificate chain was + * unacceptable (e.g., it was not signed by a known, trusted CA), the server MAY at its + * discretion either continue the handshake (considering the client unauthenticated) or send + * a fatal alert. + */ + this.tlsServer.notifyClientCertificate(clientCertificate); + } + + protected void receiveCertificateMessage(ByteArrayInputStream buf) + throws IOException + { + Certificate clientCertificate = Certificate.parse(getContext(), buf); + + assertEmpty(buf); + + notifyClientCertificate(clientCertificate); + } + + protected void receiveCertificateVerifyMessage(ByteArrayInputStream buf) + throws IOException + { + if (certificateRequest == null) + { + throw new IllegalStateException(); + } + + DigitallySigned clientCertificateVerify = DigitallySigned.parse(getContext(), buf); + + assertEmpty(buf); + + // Verify the CertificateVerify message contains a correct signature. + try + { + SignatureAndHashAlgorithm signatureAlgorithm = clientCertificateVerify.getAlgorithm(); + + byte[] hash; + if (TlsUtils.isTLSv12(getContext())) + { + TlsUtils.verifySupportedSignatureAlgorithm(certificateRequest.getSupportedSignatureAlgorithms(), signatureAlgorithm); + hash = prepareFinishHash.getFinalHash(signatureAlgorithm.getHash()); + } + else + { + hash = securityParameters.getSessionHash(); + } + + TlsVerifier verifier = peerCertificate.getCertificateAt(0) + .createVerifier(TlsUtils.getSignatureAlgorithmClient(clientCertificateType)); + + if (!verifier.verifySignature(clientCertificateVerify, hash)) + { + throw new TlsFatalAlert(AlertDescription.decrypt_error); + } + } + catch (TlsFatalAlert e) + { + throw e; + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.decrypt_error, e); + } + } + + protected void receiveClientHelloMessage(ByteArrayInputStream buf) + throws IOException + { + ProtocolVersion client_version = TlsUtils.readVersion(buf); + recordStream.setWriteVersion(client_version); + + if (client_version.isDTLS()) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + byte[] client_random = TlsUtils.readFully(32, buf); + + /* + * TODO RFC 5077 3.4. If a ticket is presented by the client, the server MUST NOT attempt to + * use the Session ID in the ClientHello for stateful session resumption. + */ + byte[] sessionID = TlsUtils.readOpaque8(buf); + if (sessionID.length > 32) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + /* + * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session + * resumption request), this vector MUST include at least the cipher_suite from that + * session. + */ + int cipher_suites_length = TlsUtils.readUint16(buf); + if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + this.offeredCipherSuites = TlsUtils.readUint16Array(cipher_suites_length / 2, buf); + + /* + * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session + * resumption request), it MUST include the compression_method from that session. + */ + int compression_methods_length = TlsUtils.readUint8(buf); + if (compression_methods_length < 1) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + this.offeredCompressionMethods = TlsUtils.readUint8Array(compression_methods_length, buf); + + /* + * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore + * extensions appearing in the client hello, and send a server hello containing no + * extensions. + */ + this.clientExtensions = readExtensions(buf); + + /* + * TODO[session-hash] + * + * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes + * that do not use the extended master secret [..]. (and see 5.2, 5.3) + */ + this.securityParameters.extendedMasterSecret = TlsExtensionsUtils.hasExtendedMasterSecretExtension(clientExtensions); + + getContextAdmin().setClientVersion(client_version); + + tlsServer.notifyClientVersion(client_version); + tlsServer.notifyFallback(Arrays.contains(offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)); + + securityParameters.clientRandom = client_random; + + tlsServer.notifyOfferedCipherSuites(offeredCipherSuites); + tlsServer.notifyOfferedCompressionMethods(offeredCompressionMethods); + + /* + * RFC 5746 3.6. Server Behavior: Initial Handshake + */ + { + /* + * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension, + * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the + * ClientHello. Including both is NOT RECOMMENDED. + */ + + /* + * When a ClientHello is received, the server MUST check if it includes the + * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag + * to TRUE. + */ + if (Arrays.contains(offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) + { + this.secure_renegotiation = true; + } + + /* + * The server MUST check if the "renegotiation_info" extension is included in the + * ClientHello. + */ + byte[] renegExtData = TlsUtils.getExtensionData(clientExtensions, EXT_RenegotiationInfo); + if (renegExtData != null) + { + /* + * If the extension is present, set secure_renegotiation flag to TRUE. The + * server MUST then verify that the length of the "renegotiated_connection" + * field is zero, and if it is not, MUST abort the handshake. + */ + this.secure_renegotiation = true; + + if (!Arrays.constantTimeAreEqual(renegExtData, createRenegotiationInfo(TlsUtils.EMPTY_BYTES))) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + } + } + + tlsServer.notifySecureRenegotiation(this.secure_renegotiation); + + if (clientExtensions != null) + { + // NOTE: Validates the padding extension data, if present + TlsExtensionsUtils.getPaddingExtension(clientExtensions); + + tlsServer.processClientExtensions(clientExtensions); + } + } + + protected void receiveClientKeyExchangeMessage(ByteArrayInputStream buf) + throws IOException + { + keyExchange.processClientKeyExchange(buf); + + assertEmpty(buf); + + if (TlsUtils.isSSL(getContext())) + { + establishMasterSecret(getContext(), keyExchange); + } + + this.prepareFinishHash = recordStream.prepareToFinish(); + this.securityParameters.sessionHash = getCurrentPRFHash(getContext(), prepareFinishHash, null); + + if (!TlsUtils.isSSL(getContext())) + { + establishMasterSecret(getContext(), keyExchange); + } + + recordStream.setPendingConnectionState(getPeer().getCompression(), getPeer().getCipher()); + + if (!expectSessionTicket) + { + sendChangeCipherSpecMessage(); + } + } + + protected void sendCertificateRequestMessage(CertificateRequest certificateRequest) + throws IOException + { + HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_request); + + certificateRequest.encode(message); + + message.writeToRecordStream(); + } + + protected void sendCertificateStatusMessage(CertificateStatus certificateStatus) + throws IOException + { + HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_status); + + certificateStatus.encode(message); + + message.writeToRecordStream(); + } + + protected void sendNewSessionTicketMessage(NewSessionTicket newSessionTicket) + throws IOException + { + if (newSessionTicket == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + HandshakeMessage message = new HandshakeMessage(HandshakeType.session_ticket); + + newSessionTicket.encode(message); + + message.writeToRecordStream(); + } + + protected void sendServerHelloMessage() + throws IOException + { + HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello); + + { + ProtocolVersion server_version = tlsServer.getServerVersion(); + if (!server_version.isEqualOrEarlierVersionOf(getContext().getClientVersion())) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + recordStream.setReadVersion(server_version); + recordStream.setWriteVersion(server_version); + recordStream.setRestrictReadVersion(true); + getContextAdmin().setServerVersion(server_version); + + TlsUtils.writeVersion(server_version, message); + } + + message.write(this.securityParameters.serverRandom); + + /* + * The server may return an empty session_id to indicate that the session will not be cached + * and therefore cannot be resumed. + */ + TlsUtils.writeOpaque8(tlsSession.getSessionID(), message); + + int selectedCipherSuite = tlsServer.getSelectedCipherSuite(); + if (!Arrays.contains(offeredCipherSuites, selectedCipherSuite) + || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL + || CipherSuite.isSCSV(selectedCipherSuite) + || !TlsUtils.isValidCipherSuiteForVersion(selectedCipherSuite, getContext().getServerVersion())) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + securityParameters.cipherSuite = selectedCipherSuite; + + short selectedCompressionMethod = tlsServer.getSelectedCompressionMethod(); + if (!Arrays.contains(offeredCompressionMethods, selectedCompressionMethod)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + securityParameters.compressionAlgorithm = selectedCompressionMethod; + + TlsUtils.writeUint16(selectedCipherSuite, message); + TlsUtils.writeUint8(selectedCompressionMethod, message); + + this.serverExtensions = tlsServer.getServerExtensions(); + + /* + * RFC 5746 3.6. Server Behavior: Initial Handshake + */ + if (this.secure_renegotiation) + { + byte[] renegExtData = TlsUtils.getExtensionData(this.serverExtensions, EXT_RenegotiationInfo); + boolean noRenegExt = (null == renegExtData); + + if (noRenegExt) + { + /* + * Note that sending a "renegotiation_info" extension in response to a ClientHello + * containing only the SCSV is an explicit exception to the prohibition in RFC 5246, + * Section 7.4.1.4, on the server sending unsolicited extensions and is only allowed + * because the client is signaling its willingness to receive the extension via the + * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. + */ + + /* + * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty + * "renegotiation_info" extension in the ServerHello message. + */ + this.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(serverExtensions); + this.serverExtensions.put(EXT_RenegotiationInfo, createRenegotiationInfo(TlsUtils.EMPTY_BYTES)); + } + } + + if (securityParameters.isExtendedMasterSecret()) + { + this.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(serverExtensions); + TlsExtensionsUtils.addExtendedMasterSecretExtension(serverExtensions); + } + + /* + * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore + * extensions appearing in the client hello, and send a server hello containing no + * extensions. + */ + + if (this.serverExtensions != null) + { + this.securityParameters.encryptThenMAC = TlsExtensionsUtils.hasEncryptThenMACExtension(serverExtensions); + + this.securityParameters.maxFragmentLength = processMaxFragmentLengthExtension(clientExtensions, + serverExtensions, AlertDescription.internal_error); + + this.securityParameters.truncatedHMac = TlsExtensionsUtils.hasTruncatedHMacExtension(serverExtensions); + + /* + * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in + * a session resumption handshake. + */ + this.allowCertificateStatus = !resumedSession + && TlsUtils.hasExpectedEmptyExtensionData(serverExtensions, TlsExtensionsUtils.EXT_status_request, + AlertDescription.internal_error); + + this.expectSessionTicket = !resumedSession + && TlsUtils.hasExpectedEmptyExtensionData(serverExtensions, TlsProtocol.EXT_SessionTicket, + AlertDescription.internal_error); + + writeExtensions(message, serverExtensions); + } + + securityParameters.prfAlgorithm = getPRFAlgorithm(getContext(), securityParameters.getCipherSuite()); + + /* + * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has + * a verify_data_length equal to 12. This includes all existing cipher suites. + */ + securityParameters.verifyDataLength = 12; + + applyMaxFragmentLengthExtension(); + + message.writeToRecordStream(); + } + + protected void sendServerHelloDoneMessage() + throws IOException + { + byte[] message = new byte[4]; + TlsUtils.writeUint8(HandshakeType.server_hello_done, message, 0); + TlsUtils.writeUint24(0, message, 1); + + writeHandshakeMessage(message, 0, message.length); + } + + protected void sendServerKeyExchangeMessage(byte[] serverKeyExchange) + throws IOException + { + HandshakeMessage message = new HandshakeMessage(HandshakeType.server_key_exchange, serverKeyExchange.length); + + message.write(serverKeyExchange); + + message.writeToRecordStream(); + } + + protected boolean expectCertificateVerifyMessage() + { + return clientCertificateType >= 0 && TlsUtils.hasSigningCapability(clientCertificateType); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSessionImpl.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSessionImpl.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSessionImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSessionImpl.java 2016-11-21 00:44:31.000000000 +0000 @@ -0,0 +1,46 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.util.Arrays; + +class TlsSessionImpl implements TlsSession +{ + final byte[] sessionID; + final SessionParameters sessionParameters; + boolean resumable; + + TlsSessionImpl(byte[] sessionID, SessionParameters sessionParameters) + { + if (sessionID == null) + { + throw new IllegalArgumentException("'sessionID' cannot be null"); + } + if (sessionID.length > 32) + { + throw new IllegalArgumentException("'sessionID' cannot be longer than 32 bytes"); + } + + this.sessionID = Arrays.clone(sessionID); + this.sessionParameters = sessionParameters; + this.resumable = sessionID.length > 0; + } + + public synchronized SessionParameters exportSessionParameters() + { + return this.sessionParameters == null ? null : this.sessionParameters.copy(); + } + + public synchronized byte[] getSessionID() + { + return sessionID; + } + + public synchronized void invalidate() + { + this.resumable = false; + } + + public synchronized boolean isResumable() + { + return resumable; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSession.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSession.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSession.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSession.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,12 @@ +package org.bouncycastle.tls; + +public interface TlsSession +{ + SessionParameters exportSessionParameters(); + + byte[] getSessionID(); + + void invalidate(); + + boolean isResumable(); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRPConfigVerifier.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRPConfigVerifier.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRPConfigVerifier.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRPConfigVerifier.java 2016-08-28 04:49:25.000000000 +0000 @@ -0,0 +1,14 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsSRPConfig; + +public interface TlsSRPConfigVerifier +{ + /** + * Check whether the given SRP configuration is acceptable for use. + * + * @param srpConfig the {@link TlsSRPConfig} to check + * @return true if (and only if) the specified configuration is acceptable + */ + boolean accept(TlsSRPConfig srpConfig); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRPIdentityManager.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRPIdentityManager.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRPIdentityManager.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRPIdentityManager.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,18 @@ +package org.bouncycastle.tls; + +public interface TlsSRPIdentityManager +{ + /** + * Lookup the {@link TlsSRPLoginParameters} corresponding to the specified identity. + * + * NOTE: To avoid "identity probing", unknown identities SHOULD be handled as recommended in RFC + * 5054 2.5.1.3. {@link SimulatedTlsSRPIdentityManager} is provided for this purpose. + * + * @param identity + * the SRP identity sent by the connecting client + * @return the {@link TlsSRPLoginParameters} for the specified identity, or else 'simulated' + * parameters if the identity is not recognized. A null value is also allowed, but not + * recommended. + */ + TlsSRPLoginParameters getLoginParameters(byte[] identity); +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRPKeyExchange.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRPKeyExchange.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRPKeyExchange.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRPKeyExchange.java 2016-10-05 01:44:43.000000000 +0000 @@ -0,0 +1,228 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.Vector; + +import org.bouncycastle.tls.crypto.TlsSRP6Client; +import org.bouncycastle.tls.crypto.TlsSRP6Server; +import org.bouncycastle.tls.crypto.TlsSRPConfig; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.tls.crypto.TlsVerifier; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; +import org.bouncycastle.util.io.TeeInputStream; + +/** + * (D)TLS SRP key exchange (RFC 5054). + */ +public class TlsSRPKeyExchange + extends AbstractTlsKeyExchange +{ + private static int checkKeyExchange(int keyExchange) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.SRP: + case KeyExchangeAlgorithm.SRP_DSS: + case KeyExchangeAlgorithm.SRP_RSA: + return keyExchange; + default: + throw new IllegalArgumentException("unsupported key exchange algorithm"); + } + } + + protected TlsSRPConfigVerifier srpConfigVerifier; + protected byte[] identity; + protected byte[] password; + + protected TlsSRPConfig srpConfig = null; + protected TlsSRP6Client srpClient = null; + protected TlsSRP6Server srpServer = null; + protected BigInteger srpPeerCredentials = null; + protected BigInteger srpVerifier = null; + protected byte[] srpSalt = null; + + protected TlsCredentialedSigner serverCredentials = null; + protected TlsVerifier verifier = null; + + public TlsSRPKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsSRPConfigVerifier srpConfigVerifier, + byte[] identity, byte[] password) + { + super(checkKeyExchange(keyExchange), supportedSignatureAlgorithms); + + this.srpConfigVerifier = srpConfigVerifier; + this.identity = identity; + this.password = password; + } + + public TlsSRPKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, byte[] identity, + TlsSRPLoginParameters loginParameters) + { + super(checkKeyExchange(keyExchange), supportedSignatureAlgorithms); + + this.identity = identity; + this.srpConfig = loginParameters.getConfig(); + this.srpVerifier = loginParameters.getVerifier(); + this.srpSalt = loginParameters.getSalt(); + } + + public void skipServerCredentials() throws IOException + { + if (keyExchange != KeyExchangeAlgorithm.SRP) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public void processServerCredentials(TlsCredentials serverCredentials) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.SRP) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + if (!(serverCredentials instanceof TlsCredentialedSigner)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.serverCredentials = (TlsCredentialedSigner)serverCredentials; + } + + public void processServerCertificate(Certificate serverCertificate) throws IOException + { + if (keyExchange == KeyExchangeAlgorithm.SRP) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + if (serverCertificate.isEmpty()) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + checkServerCertSigAlg(serverCertificate); + + this.verifier = serverCertificate.getCertificateAt(0) + .createVerifier(TlsUtils.getSignatureAlgorithm(keyExchange)); + } + + public boolean requiresServerKeyExchange() + { + return true; + } + + public byte[] generateServerKeyExchange() throws IOException + { + srpServer = context.getCrypto().createSRP6Server(srpConfig, srpVerifier); + + BigInteger B = srpServer.generateServerCredentials(); + + BigInteger[] ng = srpConfig.getExplicitNG(); + ServerSRPParams srpParams = new ServerSRPParams(ng[0], ng[1], srpSalt, B); + + DigestInputBuffer buf = new DigestInputBuffer(); + + srpParams.encode(buf); + + if (serverCredentials != null) + { + DigitallySigned signedParams = TlsUtils.generateServerKeyExchangeSignature(context, serverCredentials, buf); + + signedParams.encode(buf); + } + + return buf.toByteArray(); + } + + public void processServerKeyExchange(InputStream input) throws IOException + { + DigestInputBuffer buf = null; + InputStream teeIn = input; + + if (keyExchange != KeyExchangeAlgorithm.SRP) + { + buf = new DigestInputBuffer(); + teeIn = new TeeInputStream(input, buf); + } + + ServerSRPParams srpParams = ServerSRPParams.parse(teeIn); + + if (buf != null) + { + DigitallySigned signedParams = parseSignature(input); + + TlsUtils.verifyServerKeyExchangeSignature(context, verifier, buf, signedParams); + } + + this.srpConfig = new TlsSRPConfig(); + srpConfig.setExplicitNG(new BigInteger[]{ srpParams.getN(), srpParams.getG() }); + + if (!srpConfigVerifier.accept(srpConfig)) + { + throw new TlsFatalAlert(AlertDescription.insufficient_security); + } + + this.srpSalt = srpParams.getS(); + + /* + * RFC 5054 2.5.3: The client MUST abort the handshake with an "illegal_parameter" alert if + * B % N = 0. + */ + this.srpPeerCredentials = validatePublicValue(srpParams.getN(), srpParams.getB()); + this.srpClient = context.getCrypto().createSRP6Client(srpConfig); + } + + public void validateCertificateRequest(CertificateRequest certificateRequest) throws IOException + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + public void processClientCredentials(TlsCredentials clientCredentials) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public void generateClientKeyExchange(OutputStream output) throws IOException + { + BigInteger A = srpClient.generateClientCredentials(srpSalt, identity, password); + TlsSRPUtils.writeSRPParameter(A, output); + + context.getSecurityParameters().srpIdentity = Arrays.clone(identity); + } + + public void processClientKeyExchange(InputStream input) throws IOException + { + /* + * RFC 5054 2.5.4: The server MUST abort the handshake with an "illegal_parameter" alert if + * A % N = 0. + */ + this.srpPeerCredentials = validatePublicValue(srpConfig.getExplicitNG()[0], TlsSRPUtils.readSRPParameter(input)); + context.getSecurityParameters().srpIdentity = Arrays.clone(identity); + } + + public TlsSecret generatePreMasterSecret() throws IOException + { + BigInteger S = srpServer != null + ? srpServer.calculateSecret(srpPeerCredentials) + : srpClient.calculateSecret(srpPeerCredentials); + + // TODO Check if this needs to be a fixed size + return context.getCrypto().createSecret(BigIntegers.asUnsignedByteArray(S)); + } + + public static BigInteger validatePublicValue(BigInteger N, BigInteger val) + throws IOException + { + val = val.mod(N); + + // Check that val % N != 0 + if (val.equals(BigInteger.ZERO)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, new IllegalArgumentException("Invalid public value: 0")); + } + + return val; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRPLoginParameters.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRPLoginParameters.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRPLoginParameters.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRPLoginParameters.java 2016-08-28 04:49:25.000000000 +0000 @@ -0,0 +1,34 @@ +package org.bouncycastle.tls; + +import java.math.BigInteger; + +import org.bouncycastle.tls.crypto.TlsSRPConfig; + +public class TlsSRPLoginParameters +{ + protected TlsSRPConfig srpConfig; + protected BigInteger verifier; + protected byte[] salt; + + public TlsSRPLoginParameters(TlsSRPConfig srpConfig, BigInteger verifier, byte[] salt) + { + this.srpConfig = srpConfig; + this.verifier = verifier; + this.salt = salt; + } + + public TlsSRPConfig getConfig() + { + return srpConfig; + } + + public byte[] getSalt() + { + return salt; + } + + public BigInteger getVerifier() + { + return verifier; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRPUtils.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRPUtils.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRPUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRPUtils.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,82 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.Hashtable; + +import org.bouncycastle.util.BigIntegers; +import org.bouncycastle.util.Integers; + +public class TlsSRPUtils +{ + public static final Integer EXT_SRP = Integers.valueOf(ExtensionType.srp); + + public static void addSRPExtension(Hashtable extensions, byte[] identity) throws IOException + { + extensions.put(EXT_SRP, createSRPExtension(identity)); + } + + public static byte[] getSRPExtension(Hashtable extensions) throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_SRP); + return extensionData == null ? null : readSRPExtension(extensionData); + } + + public static byte[] createSRPExtension(byte[] identity) throws IOException + { + if (identity == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + return TlsUtils.encodeOpaque8(identity); + } + + public static byte[] readSRPExtension(byte[] extensionData) throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(extensionData); + byte[] identity = TlsUtils.readOpaque8(buf); + + TlsProtocol.assertEmpty(buf); + + return identity; + } + + public static BigInteger readSRPParameter(InputStream input) throws IOException + { + return new BigInteger(1, TlsUtils.readOpaque16(input)); + } + + public static void writeSRPParameter(BigInteger x, OutputStream output) throws IOException + { + TlsUtils.writeOpaque16(BigIntegers.asUnsignedByteArray(x), output); + } + + public static boolean isSRPCipherSuite(int cipherSuite) + { + switch (cipherSuite) + { + case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: + return true; + + default: + return false; + } + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRTPUtils.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRTPUtils.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsSRTPUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsSRTPUtils.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,74 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Hashtable; + +import org.bouncycastle.util.Integers; + +/** + * RFC 5764 DTLS Extension to Establish Keys for SRTP. + */ +public class TlsSRTPUtils +{ + public static final Integer EXT_use_srtp = Integers.valueOf(ExtensionType.use_srtp); + + public static void addUseSRTPExtension(Hashtable extensions, UseSRTPData useSRTPData) + throws IOException + { + extensions.put(EXT_use_srtp, createUseSRTPExtension(useSRTPData)); + } + + public static UseSRTPData getUseSRTPExtension(Hashtable extensions) + throws IOException + { + byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_use_srtp); + return extensionData == null ? null : readUseSRTPExtension(extensionData); + } + + public static byte[] createUseSRTPExtension(UseSRTPData useSRTPData) + throws IOException + { + if (useSRTPData == null) + { + throw new IllegalArgumentException("'useSRTPData' cannot be null"); + } + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + // SRTPProtectionProfiles + TlsUtils.writeUint16ArrayWithUint16Length(useSRTPData.getProtectionProfiles(), buf); + + // srtp_mki + TlsUtils.writeOpaque8(useSRTPData.getMki(), buf); + + return buf.toByteArray(); + } + + public static UseSRTPData readUseSRTPExtension(byte[] extensionData) + throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(extensionData); + + // SRTPProtectionProfiles + int length = TlsUtils.readUint16(buf); + if (length < 2 || (length & 1) != 0) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + int[] protectionProfiles = TlsUtils.readUint16Array(length / 2, buf); + + // srtp_mki + byte[] mki = TlsUtils.readOpaque8(buf); + + TlsProtocol.assertEmpty(buf); + + return new UseSRTPData(protectionProfiles, mki); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java 2016-11-18 12:47:10.000000000 +0000 @@ -0,0 +1,2361 @@ +package org.bouncycastle.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsHash; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.tls.crypto.TlsVerifier; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Integers; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.io.Streams; + +/** + * Some helper functions for the TLS API. + */ +public class TlsUtils +{ + public static final byte[] EMPTY_BYTES = new byte[0]; + public static final short[] EMPTY_SHORTS = new short[0]; + public static final int[] EMPTY_INTS = new int[0]; + public static final long[] EMPTY_LONGS = new long[0]; + + public static final Integer EXT_signature_algorithms = Integers.valueOf(ExtensionType.signature_algorithms); + + protected static short MINIMUM_HASH_STRICT = HashAlgorithm.sha1; + protected static short MINIMUM_HASH_PREFERRED = HashAlgorithm.sha256; + + public static void checkUint8(short i) throws IOException + { + if (!isValidUint8(i)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static void checkUint8(int i) throws IOException + { + if (!isValidUint8(i)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static void checkUint8(long i) throws IOException + { + if (!isValidUint8(i)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static void checkUint16(int i) throws IOException + { + if (!isValidUint16(i)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static void checkUint16(long i) throws IOException + { + if (!isValidUint16(i)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static void checkUint24(int i) throws IOException + { + if (!isValidUint24(i)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static void checkUint24(long i) throws IOException + { + if (!isValidUint24(i)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static void checkUint32(long i) throws IOException + { + if (!isValidUint32(i)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static void checkUint48(long i) throws IOException + { + if (!isValidUint48(i)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static void checkUint64(long i) throws IOException + { + if (!isValidUint64(i)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + public static boolean isValidUint8(short i) + { + return (i & 0xFF) == i; + } + + public static boolean isValidUint8(int i) + { + return (i & 0xFF) == i; + } + + public static boolean isValidUint8(long i) + { + return (i & 0xFFL) == i; + } + + public static boolean isValidUint16(int i) + { + return (i & 0xFFFF) == i; + } + + public static boolean isValidUint16(long i) + { + return (i & 0xFFFFL) == i; + } + + public static boolean isValidUint24(int i) + { + return (i & 0xFFFFFF) == i; + } + + public static boolean isValidUint24(long i) + { + return (i & 0xFFFFFFL) == i; + } + + public static boolean isValidUint32(long i) + { + return (i & 0xFFFFFFFFL) == i; + } + + public static boolean isValidUint48(long i) + { + return (i & 0xFFFFFFFFFFFFL) == i; + } + + public static boolean isValidUint64(long i) + { + return true; + } + + public static boolean isSSL(TlsContext context) + { + return context.getServerVersion().isSSL(); + } + + public static boolean isTLSv11(ProtocolVersion version) + { + return ProtocolVersion.TLSv11.isEqualOrEarlierVersionOf(version.getEquivalentTLSVersion()); + } + + public static boolean isTLSv11(TlsContext context) + { + return isTLSv11(context.getServerVersion()); + } + + public static boolean isTLSv12(ProtocolVersion version) + { + return ProtocolVersion.TLSv12.isEqualOrEarlierVersionOf(version.getEquivalentTLSVersion()); + } + + public static boolean isTLSv12(TlsContext context) + { + return isTLSv12(context.getServerVersion()); + } + + public static void writeUint8(short i, OutputStream output) + throws IOException + { + output.write(i); + } + + public static void writeUint8(int i, OutputStream output) + throws IOException + { + output.write(i); + } + + public static void writeUint8(short i, byte[] buf, int offset) + { + buf[offset] = (byte)i; + } + + public static void writeUint8(int i, byte[] buf, int offset) + { + buf[offset] = (byte)i; + } + + public static void writeUint16(int i, OutputStream output) + throws IOException + { + output.write(i >>> 8); + output.write(i); + } + + public static void writeUint16(int i, byte[] buf, int offset) + { + buf[offset] = (byte)(i >>> 8); + buf[offset + 1] = (byte)i; + } + + public static void writeUint24(int i, OutputStream output) + throws IOException + { + output.write((byte)(i >>> 16)); + output.write((byte)(i >>> 8)); + output.write((byte)i); + } + + public static void writeUint24(int i, byte[] buf, int offset) + { + buf[offset] = (byte)(i >>> 16); + buf[offset + 1] = (byte)(i >>> 8); + buf[offset + 2] = (byte)i; + } + + public static void writeUint32(long i, OutputStream output) + throws IOException + { + output.write((byte)(i >>> 24)); + output.write((byte)(i >>> 16)); + output.write((byte)(i >>> 8)); + output.write((byte)i); + } + + public static void writeUint32(long i, byte[] buf, int offset) + { + buf[offset] = (byte)(i >>> 24); + buf[offset + 1] = (byte)(i >>> 16); + buf[offset + 2] = (byte)(i >>> 8); + buf[offset + 3] = (byte)i; + } + + public static void writeUint48(long i, OutputStream output) + throws IOException + { + output.write((byte)(i >>> 40)); + output.write((byte)(i >>> 32)); + output.write((byte)(i >>> 24)); + output.write((byte)(i >>> 16)); + output.write((byte)(i >>> 8)); + output.write((byte)i); + } + + public static void writeUint48(long i, byte[] buf, int offset) + { + buf[offset] = (byte)(i >>> 40); + buf[offset + 1] = (byte)(i >>> 32); + buf[offset + 2] = (byte)(i >>> 24); + buf[offset + 3] = (byte)(i >>> 16); + buf[offset + 4] = (byte)(i >>> 8); + buf[offset + 5] = (byte)i; + } + + public static void writeUint64(long i, OutputStream output) + throws IOException + { + output.write((byte)(i >>> 56)); + output.write((byte)(i >>> 48)); + output.write((byte)(i >>> 40)); + output.write((byte)(i >>> 32)); + output.write((byte)(i >>> 24)); + output.write((byte)(i >>> 16)); + output.write((byte)(i >>> 8)); + output.write((byte)i); + } + + public static void writeUint64(long i, byte[] buf, int offset) + { + buf[offset] = (byte)(i >>> 56); + buf[offset + 1] = (byte)(i >>> 48); + buf[offset + 2] = (byte)(i >>> 40); + buf[offset + 3] = (byte)(i >>> 32); + buf[offset + 4] = (byte)(i >>> 24); + buf[offset + 5] = (byte)(i >>> 16); + buf[offset + 6] = (byte)(i >>> 8); + buf[offset + 7] = (byte)i; + } + + public static void writeOpaque8(byte[] buf, OutputStream output) + throws IOException + { + checkUint8(buf.length); + writeUint8(buf.length, output); + output.write(buf); + } + + public static void writeOpaque16(byte[] buf, OutputStream output) + throws IOException + { + checkUint16(buf.length); + writeUint16(buf.length, output); + output.write(buf); + } + + public static void writeOpaque24(byte[] buf, OutputStream output) + throws IOException + { + checkUint24(buf.length); + writeUint24(buf.length, output); + output.write(buf); + } + + public static void writeUint8Array(short[] uints, OutputStream output) + throws IOException + { + for (int i = 0; i < uints.length; ++i) + { + writeUint8(uints[i], output); + } + } + + public static void writeUint8Array(short[] uints, byte[] buf, int offset) + throws IOException + { + for (int i = 0; i < uints.length; ++i) + { + writeUint8(uints[i], buf, offset); + ++offset; + } + } + + public static void writeUint8ArrayWithUint8Length(short[] uints, OutputStream output) + throws IOException + { + checkUint8(uints.length); + writeUint8(uints.length, output); + writeUint8Array(uints, output); + } + + public static void writeUint8ArrayWithUint8Length(short[] uints, byte[] buf, int offset) + throws IOException + { + checkUint8(uints.length); + writeUint8(uints.length, buf, offset); + writeUint8Array(uints, buf, offset + 1); + } + + public static void writeUint16Array(int[] uints, OutputStream output) + throws IOException + { + for (int i = 0; i < uints.length; ++i) + { + writeUint16(uints[i], output); + } + } + + public static void writeUint16Array(int[] uints, byte[] buf, int offset) + throws IOException + { + for (int i = 0; i < uints.length; ++i) + { + writeUint16(uints[i], buf, offset); + offset += 2; + } + } + + public static void writeUint16ArrayWithUint16Length(int[] uints, OutputStream output) + throws IOException + { + int length = 2 * uints.length; + checkUint16(length); + writeUint16(length, output); + writeUint16Array(uints, output); + } + + public static void writeUint16ArrayWithUint16Length(int[] uints, byte[] buf, int offset) + throws IOException + { + int length = 2 * uints.length; + checkUint16(length); + writeUint16(length, buf, offset); + writeUint16Array(uints, buf, offset + 2); + } + + public static byte[] encodeOpaque8(byte[] buf) + throws IOException + { + checkUint8(buf.length); + return Arrays.prepend(buf, (byte)buf.length); + } + + public static byte[] encodeUint8ArrayWithUint8Length(short[] uints) throws IOException + { + byte[] result = new byte[1 + uints.length]; + writeUint8ArrayWithUint8Length(uints, result, 0); + return result; + } + + public static byte[] encodeUint16ArrayWithUint16Length(int[] uints) throws IOException + { + int length = 2 * uints.length; + byte[] result = new byte[2 + length]; + writeUint16ArrayWithUint16Length(uints, result, 0); + return result; + } + + public static short readUint8(InputStream input) + throws IOException + { + int i = input.read(); + if (i < 0) + { + throw new EOFException(); + } + return (short)i; + } + + public static short readUint8(byte[] buf, int offset) + { + return (short)(buf[offset] & 0xff); + } + + public static int readUint16(InputStream input) + throws IOException + { + int i1 = input.read(); + int i2 = input.read(); + if (i2 < 0) + { + throw new EOFException(); + } + return (i1 << 8) | i2; + } + + public static int readUint16(byte[] buf, int offset) + { + int n = (buf[offset] & 0xff) << 8; + n |= (buf[++offset] & 0xff); + return n; + } + + public static int readUint24(InputStream input) + throws IOException + { + int i1 = input.read(); + int i2 = input.read(); + int i3 = input.read(); + if (i3 < 0) + { + throw new EOFException(); + } + return (i1 << 16) | (i2 << 8) | i3; + } + + public static int readUint24(byte[] buf, int offset) + { + int n = (buf[offset] & 0xff) << 16; + n |= (buf[++offset] & 0xff) << 8; + n |= (buf[++offset] & 0xff); + return n; + } + + public static long readUint32(InputStream input) + throws IOException + { + int i1 = input.read(); + int i2 = input.read(); + int i3 = input.read(); + int i4 = input.read(); + if (i4 < 0) + { + throw new EOFException(); + } + return ((i1 << 24) | (i2 << 16) | (i3 << 8) | i4) & 0xFFFFFFFFL; + } + + public static long readUint32(byte[] buf, int offset) + { + int n = (buf[offset] & 0xff) << 24; + n |= (buf[++offset] & 0xff) << 16; + n |= (buf[++offset] & 0xff) << 8; + n |= (buf[++offset] & 0xff); + return n & 0xFFFFFFFFL; + } + + public static long readUint48(InputStream input) + throws IOException + { + int hi = readUint24(input); + int lo = readUint24(input); + return ((long)(hi & 0xffffffffL) << 24) | (long)(lo & 0xffffffffL); + } + + public static long readUint48(byte[] buf, int offset) + { + int hi = readUint24(buf, offset); + int lo = readUint24(buf, offset + 3); + return ((long)(hi & 0xffffffffL) << 24) | (long)(lo & 0xffffffffL); + } + + public static byte[] readAllOrNothing(int length, InputStream input) + throws IOException + { + if (length < 1) + { + return EMPTY_BYTES; + } + byte[] buf = new byte[length]; + int read = Streams.readFully(input, buf); + if (read == 0) + { + return null; + } + if (read != length) + { + throw new EOFException(); + } + return buf; + } + + public static byte[] readFully(int length, InputStream input) + throws IOException + { + if (length < 1) + { + return EMPTY_BYTES; + } + byte[] buf = new byte[length]; + if (length != Streams.readFully(input, buf)) + { + throw new EOFException(); + } + return buf; + } + + public static void readFully(byte[] buf, InputStream input) + throws IOException + { + int length = buf.length; + if (length > 0 && length != Streams.readFully(input, buf)) + { + throw new EOFException(); + } + } + + public static byte[] readOpaque8(InputStream input) + throws IOException + { + short length = readUint8(input); + return readFully(length, input); + } + + public static byte[] readOpaque16(InputStream input) + throws IOException + { + int length = readUint16(input); + return readFully(length, input); + } + + public static byte[] readOpaque24(InputStream input) + throws IOException + { + int length = readUint24(input); + return readFully(length, input); + } + + public static short[] readUint8Array(int count, InputStream input) + throws IOException + { + short[] uints = new short[count]; + for (int i = 0; i < count; ++i) + { + uints[i] = readUint8(input); + } + return uints; + } + + public static int[] readUint16Array(int count, InputStream input) + throws IOException + { + int[] uints = new int[count]; + for (int i = 0; i < count; ++i) + { + uints[i] = readUint16(input); + } + return uints; + } + + public static ProtocolVersion readVersion(byte[] buf, int offset) + throws IOException + { + return ProtocolVersion.get(buf[offset] & 0xFF, buf[offset + 1] & 0xFF); + } + + public static ProtocolVersion readVersion(InputStream input) + throws IOException + { + int i1 = input.read(); + int i2 = input.read(); + if (i2 < 0) + { + throw new EOFException(); + } + return ProtocolVersion.get(i1, i2); + } + + public static int readVersionRaw(byte[] buf, int offset) + throws IOException + { + return (buf[offset] << 8) | buf[offset + 1]; + } + + public static int readVersionRaw(InputStream input) + throws IOException + { + int i1 = input.read(); + int i2 = input.read(); + if (i2 < 0) + { + throw new EOFException(); + } + return (i1 << 8) | i2; + } + + public static ASN1Primitive readASN1Object(byte[] encoding) throws IOException + { + ASN1InputStream asn1 = new ASN1InputStream(encoding); + ASN1Primitive result = asn1.readObject(); + if (null == result) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + if (null != asn1.readObject()) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + return result; + } + + public static ASN1Primitive readDERObject(byte[] encoding) throws IOException + { + /* + * NOTE: The current ASN.1 parsing code can't enforce DER-only parsing, but since DER is + * canonical, we can check it by re-encoding the result and comparing to the original. + */ + ASN1Primitive result = readASN1Object(encoding); + byte[] check = result.getEncoded(ASN1Encoding.DER); + if (!Arrays.areEqual(check, encoding)) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + return result; + } + + public static void writeGMTUnixTime(byte[] buf, int offset) + { + int t = (int)(System.currentTimeMillis() / 1000L); + buf[offset] = (byte)(t >>> 24); + buf[offset + 1] = (byte)(t >>> 16); + buf[offset + 2] = (byte)(t >>> 8); + buf[offset + 3] = (byte)t; + } + + public static void writeVersion(ProtocolVersion version, OutputStream output) + throws IOException + { + output.write(version.getMajorVersion()); + output.write(version.getMinorVersion()); + } + + public static void writeVersion(ProtocolVersion version, byte[] buf, int offset) + { + buf[offset] = (byte)version.getMajorVersion(); + buf[offset + 1] = (byte)version.getMinorVersion(); + } + + public static Vector getDefaultDSSSignatureAlgorithms() + { + return vectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.dsa)); + } + + public static Vector getDefaultECDSASignatureAlgorithms() + { + return vectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa)); + } + + public static Vector getDefaultRSASignatureAlgorithms() + { + return vectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa)); + } + + public static Vector getDefaultSignatureAlgorithms(int signatureAlgorithm) + { + switch (signatureAlgorithm) + { + case SignatureAlgorithm.dsa: + return getDefaultDSSSignatureAlgorithms(); + case SignatureAlgorithm.ecdsa: + return getDefaultECDSASignatureAlgorithms(); + case SignatureAlgorithm.rsa: + return getDefaultRSASignatureAlgorithms(); + default: + throw new IllegalArgumentException("unknown SignatureAlgorithm"); + } + } + + public static Vector getDefaultSupportedSignatureAlgorithms() + { + short[] hashAlgorithms = new short[]{ HashAlgorithm.sha1, HashAlgorithm.sha224, HashAlgorithm.sha256, + HashAlgorithm.sha384, HashAlgorithm.sha512 }; + short[] signatureAlgorithms = new short[]{ SignatureAlgorithm.rsa, SignatureAlgorithm.dsa, + SignatureAlgorithm.ecdsa }; + + Vector result = new Vector(); + for (int i = 0; i < signatureAlgorithms.length; ++i) + { + for (int j = 0; j < hashAlgorithms.length; ++j) + { + result.addElement(new SignatureAndHashAlgorithm(hashAlgorithms[j], signatureAlgorithms[i])); + } + } + return result; + } + + public static SignatureAndHashAlgorithm getSignatureAndHashAlgorithm(TlsContext context, + TlsCredentialedSigner signerCredentials) + throws IOException + { + SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; + if (isTLSv12(context)) + { + signatureAndHashAlgorithm = signerCredentials.getSignatureAndHashAlgorithm(); + if (signatureAndHashAlgorithm == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + return signatureAndHashAlgorithm; + } + + public static byte[] getExtensionData(Hashtable extensions, Integer extensionType) + { + return extensions == null ? null : (byte[])extensions.get(extensionType); + } + + public static boolean hasExpectedEmptyExtensionData(Hashtable extensions, Integer extensionType, + short alertDescription) throws IOException + { + byte[] extension_data = getExtensionData(extensions, extensionType); + if (extension_data == null) + { + return false; + } + if (extension_data.length != 0) + { + throw new TlsFatalAlert(alertDescription); + } + return true; + } + + public static TlsSession importSession(byte[] sessionID, SessionParameters sessionParameters) + { + return new TlsSessionImpl(sessionID, sessionParameters); + } + + public static boolean isSignatureAlgorithmsExtensionAllowed(ProtocolVersion clientVersion) + { + return ProtocolVersion.TLSv12.isEqualOrEarlierVersionOf(clientVersion.getEquivalentTLSVersion()); + } + + /** + * Add a 'signature_algorithms' extension to existing extensions. + * + * @param extensions A {@link Hashtable} to add the extension to. + * @param supportedSignatureAlgorithms {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}. + * @throws IOException + */ + public static void addSignatureAlgorithmsExtension(Hashtable extensions, Vector supportedSignatureAlgorithms) + throws IOException + { + extensions.put(EXT_signature_algorithms, createSignatureAlgorithmsExtension(supportedSignatureAlgorithms)); + } + + public static short getSignatureAlgorithm(int keyExchangeAlgorithm) + { + switch (keyExchangeAlgorithm) + { + case KeyExchangeAlgorithm.DH_DSS: + case KeyExchangeAlgorithm.DH_DSS_EXPORT: + case KeyExchangeAlgorithm.DHE_DSS: + case KeyExchangeAlgorithm.DHE_DSS_EXPORT: + case KeyExchangeAlgorithm.SRP_DSS: + return SignatureAlgorithm.dsa; + + case KeyExchangeAlgorithm.ECDH_ECDSA: + case KeyExchangeAlgorithm.ECDHE_ECDSA: + return SignatureAlgorithm.ecdsa; + + case KeyExchangeAlgorithm.DH_RSA: + case KeyExchangeAlgorithm.DH_RSA_EXPORT: + case KeyExchangeAlgorithm.DHE_RSA: + case KeyExchangeAlgorithm.DHE_RSA_EXPORT: + case KeyExchangeAlgorithm.ECDH_RSA: + case KeyExchangeAlgorithm.ECDHE_RSA: + case KeyExchangeAlgorithm.SRP_RSA: + return SignatureAlgorithm.rsa; + + default: + return -1; + } + } + + public static short getSignatureAlgorithmClient(short clientCertificateType) + { + switch (clientCertificateType) + { + case ClientCertificateType.dss_sign: + return SignatureAlgorithm.dsa; + case ClientCertificateType.ecdsa_sign: + return SignatureAlgorithm.ecdsa; + case ClientCertificateType.rsa_sign: + return SignatureAlgorithm.rsa; + default: + return -1; + } + } + + /** + * Get a 'signature_algorithms' extension from extensions. + * + * @param extensions A {@link Hashtable} to get the extension from, if it is present. + * @return A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}, or null. + * @throws IOException + */ + public static Vector getSignatureAlgorithmsExtension(Hashtable extensions) + throws IOException + { + byte[] extensionData = getExtensionData(extensions, EXT_signature_algorithms); + return extensionData == null ? null : readSignatureAlgorithmsExtension(extensionData); + } + + /** + * Create a 'signature_algorithms' extension value. + * + * @param supportedSignatureAlgorithms A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}. + * @return A byte array suitable for use as an extension value. + * @throws IOException + */ + public static byte[] createSignatureAlgorithmsExtension(Vector supportedSignatureAlgorithms) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + // supported_signature_algorithms + encodeSupportedSignatureAlgorithms(supportedSignatureAlgorithms, false, buf); + + return buf.toByteArray(); + } + + /** + * Read 'signature_algorithms' extension data. + * + * @param extensionData The extension data. + * @return A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}. + * @throws IOException + */ + public static Vector readSignatureAlgorithmsExtension(byte[] extensionData) + throws IOException + { + if (extensionData == null) + { + throw new IllegalArgumentException("'extensionData' cannot be null"); + } + + ByteArrayInputStream buf = new ByteArrayInputStream(extensionData); + + // supported_signature_algorithms + Vector supported_signature_algorithms = parseSupportedSignatureAlgorithms(false, buf); + + TlsProtocol.assertEmpty(buf); + + return supported_signature_algorithms; + } + + public static void encodeSupportedSignatureAlgorithms(Vector supportedSignatureAlgorithms, boolean allowAnonymous, + OutputStream output) throws IOException + { + if (supportedSignatureAlgorithms == null || supportedSignatureAlgorithms.size() < 1 + || supportedSignatureAlgorithms.size() >= (1 << 15)) + { + throw new IllegalArgumentException( + "'supportedSignatureAlgorithms' must have length from 1 to (2^15 - 1)"); + } + + // supported_signature_algorithms + int length = 2 * supportedSignatureAlgorithms.size(); + checkUint16(length); + writeUint16(length, output); + for (int i = 0; i < supportedSignatureAlgorithms.size(); ++i) + { + SignatureAndHashAlgorithm entry = (SignatureAndHashAlgorithm)supportedSignatureAlgorithms.elementAt(i); + if (!allowAnonymous && entry.getSignature() == SignatureAlgorithm.anonymous) + { + /* + * RFC 5246 7.4.1.4.1 The "anonymous" value is meaningless in this context but used + * in Section 7.4.3. It MUST NOT appear in this extension. + */ + throw new IllegalArgumentException( + "SignatureAlgorithm.anonymous MUST NOT appear in the signature_algorithms extension"); + } + entry.encode(output); + } + } + + public static Vector parseSupportedSignatureAlgorithms(boolean allowAnonymous, InputStream input) + throws IOException + { + // supported_signature_algorithms + int length = readUint16(input); + if (length < 2 || (length & 1) != 0) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + int count = length / 2; + Vector supportedSignatureAlgorithms = new Vector(count); + for (int i = 0; i < count; ++i) + { + SignatureAndHashAlgorithm entry = SignatureAndHashAlgorithm.parse(input); + if (!allowAnonymous && entry.getSignature() == SignatureAlgorithm.anonymous) + { + /* + * RFC 5246 7.4.1.4.1 The "anonymous" value is meaningless in this context but used + * in Section 7.4.3. It MUST NOT appear in this extension. + */ + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + supportedSignatureAlgorithms.addElement(entry); + } + return supportedSignatureAlgorithms; + } + + public static void verifySupportedSignatureAlgorithm(Vector supportedSignatureAlgorithms, SignatureAndHashAlgorithm signatureAlgorithm) + throws IOException + { + if (supportedSignatureAlgorithms == null || supportedSignatureAlgorithms.size() < 1 + || supportedSignatureAlgorithms.size() >= (1 << 15)) + { + throw new IllegalArgumentException( + "'supportedSignatureAlgorithms' must have length from 1 to (2^15 - 1)"); + } + if (signatureAlgorithm == null) + { + throw new IllegalArgumentException("'signatureAlgorithm' cannot be null"); + } + + if (signatureAlgorithm.getSignature() != SignatureAlgorithm.anonymous) + { + for (int i = 0; i < supportedSignatureAlgorithms.size(); ++i) + { + SignatureAndHashAlgorithm entry = (SignatureAndHashAlgorithm)supportedSignatureAlgorithms.elementAt(i); + if (entry.getHash() == signatureAlgorithm.getHash() && entry.getSignature() == signatureAlgorithm.getSignature()) + { + return; + } + } + } + + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + public static TlsSecret PRF(TlsContext context, TlsSecret secret, String asciiLabel, byte[] seed, int length) + { + ProtocolVersion version = context.getServerVersion(); + + if (version.isSSL()) + { + throw new IllegalStateException("No PRF available for SSLv3 session"); + } + + byte[] label = Strings.toByteArray(asciiLabel); + byte[] labelSeed = concat(label, seed); + + int prfAlgorithm = context.getSecurityParameters().getPrfAlgorithm(); + + return secret.deriveUsingPRF(prfAlgorithm, labelSeed, length); + } + + static byte[] concat(byte[] a, byte[] b) + { + byte[] c = new byte[a.length + b.length]; + System.arraycopy(a, 0, c, 0, a.length); + System.arraycopy(b, 0, c, a.length, b.length); + return c; + } + + static TlsSecret calculateMasterSecret(TlsContext context, TlsSecret preMasterSecret) + { + SecurityParameters securityParameters = context.getSecurityParameters(); + + byte[] seed; + if (securityParameters.isExtendedMasterSecret()) + { + seed = securityParameters.getSessionHash(); + } + else + { + seed = concat(securityParameters.getClientRandom(), securityParameters.getServerRandom()); + } + + if (isSSL(context)) + { + return preMasterSecret.deriveSSLMasterSecret(seed); + } + + String asciiLabel = securityParameters.isExtendedMasterSecret() + ? ExporterLabel.extended_master_secret + : ExporterLabel.master_secret; + + return PRF(context, preMasterSecret, asciiLabel, seed, 48); + } + + static byte[] calculateVerifyData(TlsContext context, String asciiLabel, byte[] handshakeHash) + { + if (isSSL(context)) + { + return handshakeHash; + } + + SecurityParameters securityParameters = context.getSecurityParameters(); + TlsSecret master_secret = securityParameters.getMasterSecret(); + int verify_data_length = securityParameters.getVerifyDataLength(); + + return PRF(context, master_secret, asciiLabel, handshakeHash, verify_data_length).extract(); + } + + public static short getHashAlgorithmForPRFAlgorithm(int prfAlgorithm) + { + switch (prfAlgorithm) + { + case PRFAlgorithm.tls_prf_legacy: + throw new IllegalArgumentException("legacy PRF not a valid algorithm"); + case PRFAlgorithm.tls_prf_sha256: + return HashAlgorithm.sha256; + case PRFAlgorithm.tls_prf_sha384: + return HashAlgorithm.sha384; + default: + throw new IllegalArgumentException("unknown PRFAlgorithm"); + } + } + + public static ASN1ObjectIdentifier getOIDForHashAlgorithm(short hashAlgorithm) + { + switch (hashAlgorithm) + { + case HashAlgorithm.md5: + return PKCSObjectIdentifiers.md5; + case HashAlgorithm.sha1: + return X509ObjectIdentifiers.id_SHA1; + case HashAlgorithm.sha224: + return NISTObjectIdentifiers.id_sha224; + case HashAlgorithm.sha256: + return NISTObjectIdentifiers.id_sha256; + case HashAlgorithm.sha384: + return NISTObjectIdentifiers.id_sha384; + case HashAlgorithm.sha512: + return NISTObjectIdentifiers.id_sha512; + default: + throw new IllegalArgumentException("unknown HashAlgorithm"); + } + } + + static byte[] calculateSignatureHash(TlsContext context, SignatureAndHashAlgorithm algorithm, DigestInputBuffer buf) + { + TlsHash h = context.getCrypto().createHash(algorithm); + + SecurityParameters securityParameters = context.getSecurityParameters(); + h.update(securityParameters.clientRandom, 0, securityParameters.clientRandom.length); + h.update(securityParameters.serverRandom, 0, securityParameters.serverRandom.length); + buf.updateDigest(h); + + return h.calculateHash(); + } + + static DigitallySigned generateServerKeyExchangeSignature(TlsContext context, TlsCredentialedSigner credentials, + DigestInputBuffer buf) throws IOException + { + /* + * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 + */ + SignatureAndHashAlgorithm algorithm = TlsUtils.getSignatureAndHashAlgorithm(context, credentials); + byte[] hash = TlsUtils.calculateSignatureHash(context, algorithm, buf); + byte[] signature = credentials.generateRawSignature(hash); + return new DigitallySigned(algorithm, signature); + } + + static void verifyServerKeyExchangeSignature(TlsContext context, TlsVerifier tlsVerifier, DigestInputBuffer buf, + DigitallySigned signedParams) throws IOException + { + byte[] hash = TlsUtils.calculateSignatureHash(context, signedParams.getAlgorithm(), buf); + + if (!tlsVerifier.verifySignature(signedParams, hash)) + { + throw new TlsFatalAlert(AlertDescription.decrypt_error); + } + } + + static short getClientCertificateType(TlsContext context, Certificate clientCertificate, Certificate serverCertificate) + throws IOException + { + if (clientCertificate.isEmpty()) + { + return -1; + } + + return clientCertificate.getCertificateAt(0).getClientCertificateType(); + } + + static void trackHashAlgorithms(TlsHandshakeHash handshakeHash, Vector supportedSignatureAlgorithms) + { + if (supportedSignatureAlgorithms != null) + { + for (int i = 0; i < supportedSignatureAlgorithms.size(); ++i) + { + SignatureAndHashAlgorithm signatureAndHashAlgorithm = (SignatureAndHashAlgorithm) + supportedSignatureAlgorithms.elementAt(i); + short hashAlgorithm = signatureAndHashAlgorithm.getHash(); + + // TODO Support values in the "Reserved for Private Use" range + if (!HashAlgorithm.isPrivate(hashAlgorithm)) + { + handshakeHash.trackHashAlgorithm(hashAlgorithm); + } + } + } + } + + public static boolean hasSigningCapability(short clientCertificateType) + { + switch (clientCertificateType) + { + case ClientCertificateType.dss_sign: + case ClientCertificateType.ecdsa_sign: + case ClientCertificateType.rsa_sign: + return true; + default: + return false; + } + } + + static final byte[] SSL_CLIENT = {0x43, 0x4C, 0x4E, 0x54}; + static final byte[] SSL_SERVER = {0x53, 0x52, 0x56, 0x52}; + + private static Vector vectorOfOne(Object obj) + { + Vector v = new Vector(1); + v.addElement(obj); + return v; + } + + public static int getCipherType(int cipherSuite) + { + switch (getEncryptionAlgorithm(cipherSuite)) + { + case EncryptionAlgorithm.AES_128_CCM: + case EncryptionAlgorithm.AES_128_CCM_8: + case EncryptionAlgorithm.AES_128_GCM: + case EncryptionAlgorithm.AES_128_OCB_TAGLEN96: + case EncryptionAlgorithm.AES_256_CCM: + case EncryptionAlgorithm.AES_256_CCM_8: + case EncryptionAlgorithm.AES_256_GCM: + case EncryptionAlgorithm.AES_256_OCB_TAGLEN96: + case EncryptionAlgorithm.CAMELLIA_128_GCM: + case EncryptionAlgorithm.CAMELLIA_256_GCM: + case EncryptionAlgorithm.CHACHA20_POLY1305: + return CipherType.aead; + + case EncryptionAlgorithm.RC2_CBC_40: + case EncryptionAlgorithm.IDEA_CBC: + case EncryptionAlgorithm.DES40_CBC: + case EncryptionAlgorithm.DES_CBC: + case EncryptionAlgorithm._3DES_EDE_CBC: + case EncryptionAlgorithm.AES_128_CBC: + case EncryptionAlgorithm.AES_256_CBC: + case EncryptionAlgorithm.CAMELLIA_128_CBC: + case EncryptionAlgorithm.CAMELLIA_256_CBC: + case EncryptionAlgorithm.SEED_CBC: + return CipherType.block; + + case EncryptionAlgorithm.NULL: + case EncryptionAlgorithm.RC4_40: + case EncryptionAlgorithm.RC4_128: + return CipherType.stream; + + default: + return -1; + } + } + + public static int getEncryptionAlgorithm(int cipherSuite) + { + switch (cipherSuite) + { + case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: + return EncryptionAlgorithm._3DES_EDE_CBC; + + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: + return EncryptionAlgorithm.AES_128_CBC; + + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256: + case CipherSuite.TLS_PSK_WITH_AES_128_CCM: + case CipherSuite.TLS_RSA_WITH_AES_128_CCM: + return EncryptionAlgorithm.AES_128_CCM; + + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256: + case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8: + case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8: + return EncryptionAlgorithm.AES_128_CCM_8; + + case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256: + return EncryptionAlgorithm.AES_128_GCM; + + case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB: + case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB: + case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB: + case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB: + case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB: + return EncryptionAlgorithm.AES_128_OCB_TAGLEN96; + + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: + return EncryptionAlgorithm.AES_256_CBC; + + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_SHA384: + case CipherSuite.TLS_PSK_WITH_AES_256_CCM: + case CipherSuite.TLS_RSA_WITH_AES_256_CCM: + return EncryptionAlgorithm.AES_256_CCM; + + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_8_SHA256: + case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8: + case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8: + return EncryptionAlgorithm.AES_256_CCM_8; + + case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384: + return EncryptionAlgorithm.AES_256_GCM; + + case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB: + case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB: + case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB: + case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB: + case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB: + return EncryptionAlgorithm.AES_256_OCB_TAGLEN96; + + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256: + return EncryptionAlgorithm.CAMELLIA_128_CBC; + + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256: + return EncryptionAlgorithm.CAMELLIA_128_GCM; + + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384: + return EncryptionAlgorithm.CAMELLIA_256_CBC; + + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: + return EncryptionAlgorithm.CAMELLIA_256_GCM; + + case CipherSuite.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256: + return EncryptionAlgorithm.CHACHA20_POLY1305; + + case CipherSuite.TLS_RSA_WITH_NULL_MD5: + return EncryptionAlgorithm.NULL; + + case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA: + case CipherSuite.TLS_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_RSA_WITH_NULL_SHA: + return EncryptionAlgorithm.NULL; + + case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_RSA_WITH_NULL_SHA256: + return EncryptionAlgorithm.NULL; + + case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384: + return EncryptionAlgorithm.NULL; + + case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5: + case CipherSuite.TLS_RSA_WITH_RC4_128_MD5: + return EncryptionAlgorithm.RC4_128; + + case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_PSK_WITH_RC4_128_SHA: + case CipherSuite.TLS_RSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA: + return EncryptionAlgorithm.RC4_128; + + case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA: + return EncryptionAlgorithm.SEED_CBC; + + default: + return -1; + } + } + + public static int getKeyExchangeAlgorithm(int cipherSuite) + { + switch (cipherSuite) + { + case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5: + case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA: + return KeyExchangeAlgorithm.DH_anon; + + case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA: + return KeyExchangeAlgorithm.DH_DSS; + + case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA: + return KeyExchangeAlgorithm.DH_RSA; + + case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA: + return KeyExchangeAlgorithm.DHE_DSS; + + case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA: + case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8: + case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8: + return KeyExchangeAlgorithm.DHE_PSK; + + case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA: + return KeyExchangeAlgorithm.DHE_RSA; + + case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA: + return KeyExchangeAlgorithm.ECDH_anon; + + case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA: + return KeyExchangeAlgorithm.ECDH_ECDSA; + + case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA: + return KeyExchangeAlgorithm.ECDH_RSA; + + case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: + return KeyExchangeAlgorithm.ECDHE_ECDSA; + + case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_8_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA: + return KeyExchangeAlgorithm.ECDHE_PSK; + + case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA: + return KeyExchangeAlgorithm.ECDHE_RSA; + + case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_PSK_WITH_AES_128_CCM: + case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB: + case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_PSK_WITH_AES_256_CCM: + case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_PSK_WITH_RC4_128_SHA: + return KeyExchangeAlgorithm.PSK; + + case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_128_CCM: + case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_256_CCM: + case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_RSA_WITH_NULL_MD5: + case CipherSuite.TLS_RSA_WITH_NULL_SHA: + case CipherSuite.TLS_RSA_WITH_NULL_SHA256: + case CipherSuite.TLS_RSA_WITH_RC4_128_MD5: + case CipherSuite.TLS_RSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA: + return KeyExchangeAlgorithm.RSA; + + case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA: + return KeyExchangeAlgorithm.RSA_PSK; + + case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: + return KeyExchangeAlgorithm.SRP; + + case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: + return KeyExchangeAlgorithm.SRP_DSS; + + case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: + return KeyExchangeAlgorithm.SRP_RSA; + + default: + return -1; + } + } + + public static int getMACAlgorithm(int cipherSuite) + { + switch (cipherSuite) + { + case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_8_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8: + case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_128_CCM: + case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB: + case CipherSuite.TLS_PSK_WITH_AES_256_CCM: + case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_128_CCM: + case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_256_CCM: + case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: + return MACAlgorithm._null; + + case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5: + case CipherSuite.TLS_RSA_WITH_NULL_MD5: + case CipherSuite.TLS_RSA_WITH_RC4_128_MD5: + return MACAlgorithm.hmac_md5; + + case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA: + case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA: + case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_PSK_WITH_RC4_128_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA: + case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA: + case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_RSA_WITH_NULL_SHA: + case CipherSuite.TLS_RSA_WITH_RC4_128_SHA: + case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: + return MACAlgorithm.hmac_sha1; + + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_NULL_SHA256: + return MACAlgorithm.hmac_sha256; + + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_PSK_WITH_NULL_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384: + return MACAlgorithm.hmac_sha384; + + default: + return -1; + } + } + + public static ProtocolVersion getMinimumVersion(int cipherSuite) + { + switch (cipherSuite) + { + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM: + case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM: + case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_8_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_CCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8: + case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_128_CCM: + case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB: + case CipherSuite.TLS_PSK_WITH_AES_256_CCM: + case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8: + case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_128_CCM: + case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8: + case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_AES_256_CCM: + case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8: + case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_RSA_WITH_NULL_SHA256: + return ProtocolVersion.TLSv12; + + default: + return ProtocolVersion.SSLv3; + } + } + + public static boolean isAEADCipherSuite(int cipherSuite) throws IOException + { + return CipherType.aead == getCipherType(cipherSuite); + } + + public static boolean isBlockCipherSuite(int cipherSuite) throws IOException + { + return CipherType.block == getCipherType(cipherSuite); + } + + public static boolean isStreamCipherSuite(int cipherSuite) throws IOException + { + return CipherType.stream == getCipherType(cipherSuite); + } + + public static boolean isValidCipherSuiteForVersion(int cipherSuite, ProtocolVersion serverVersion) + { + return getMinimumVersion(cipherSuite).isEqualOrEarlierVersionOf(serverVersion.getEquivalentTLSVersion()); + } + + public static SignatureAndHashAlgorithm chooseSignatureAndHashAlgorithm(TlsContext context, Vector algs, int signatureAlgorithm) + throws IOException + { + if (!TlsUtils.isTLSv12(context)) + { + return null; + } + + if (algs == null) + { + algs = TlsUtils.getDefaultSignatureAlgorithms(signatureAlgorithm); + } + + SignatureAndHashAlgorithm result = null; + for (int i = 0; i < algs.size(); ++i) + { + SignatureAndHashAlgorithm alg = (SignatureAndHashAlgorithm)algs.elementAt(i); + if (alg.getSignature() == signatureAlgorithm) + { + short hash = alg.getHash(); + if (hash < MINIMUM_HASH_STRICT) + { + continue; + } + if (result == null) + { + result = alg; + continue; + } + + short current = result.getHash(); + if (hash < MINIMUM_HASH_PREFERRED) + { + if (hash > current) + { + result = alg; + } + } + else + { + if (hash < current) + { + result = alg; + } + } + } + } + if (result == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + return result; + } + + public static int[] getSupportedCipherSuites(TlsCrypto crypto, int[] baseCipherSuiteList) + { + List supported = new ArrayList(); + + for (int i = 0; i != baseCipherSuiteList.length; i++) + { + int cipherSuite = baseCipherSuiteList[i]; + int encryptionAlgorithm = TlsUtils.getEncryptionAlgorithm(cipherSuite); + int macAlgorithm = TlsUtils.getMACAlgorithm(cipherSuite); + + if (crypto.hasEncryptionAlgorithm(encryptionAlgorithm) && crypto.hasMacAlgorithm(macAlgorithm)) + { + supported.add(baseCipherSuiteList[i]); + } + } + + int[] rv = new int[supported.size()]; + + for (int i = 0; i != rv.length; i++) + { + rv[i] = supported.get(i); + } + + return rv; + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/UDPTransport.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/UDPTransport.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/UDPTransport.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/UDPTransport.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,75 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; + +public class UDPTransport + implements DatagramTransport +{ + protected final static int MIN_IP_OVERHEAD = 20; + protected final static int MAX_IP_OVERHEAD = MIN_IP_OVERHEAD + 64; + protected final static int UDP_OVERHEAD = 8; + + protected final DatagramSocket socket; + protected final int receiveLimit, sendLimit; + + public UDPTransport(DatagramSocket socket, int mtu) + throws IOException + { + if (!socket.isBound() || !socket.isConnected()) + { + throw new IllegalArgumentException("'socket' must be bound and connected"); + } + + this.socket = socket; + + // NOTE: As of JDK 1.6, can use NetworkInterface.getMTU + + this.receiveLimit = mtu - MIN_IP_OVERHEAD - UDP_OVERHEAD; + this.sendLimit = mtu - MAX_IP_OVERHEAD - UDP_OVERHEAD; + } + + public int getReceiveLimit() + { + return receiveLimit; + } + + public int getSendLimit() + { + // TODO[DTLS] Implement Path-MTU discovery? + return sendLimit; + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + socket.setSoTimeout(waitMillis); + DatagramPacket packet = new DatagramPacket(buf, off, len); + socket.receive(packet); + return packet.getLength(); + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + if (len > getSendLimit()) + { + /* + * RFC 4347 4.1.1. "If the application attempts to send a record larger than the MTU, + * the DTLS implementation SHOULD generate an error, thus avoiding sending a packet + * which will be fragmented." + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + DatagramPacket packet = new DatagramPacket(buf, off, len); + socket.send(packet); + } + + public void close() + throws IOException + { + socket.close(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/URLAndHash.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/URLAndHash.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/URLAndHash.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/URLAndHash.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,104 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.bouncycastle.util.Strings; + +/** + * RFC 6066 5. + */ +public class URLAndHash +{ + protected String url; + protected byte[] sha1Hash; + + public URLAndHash(String url, byte[] sha1Hash) + { + if (url == null || url.length() < 1 || url.length() >= (1 << 16)) + { + throw new IllegalArgumentException("'url' must have length from 1 to (2^16 - 1)"); + } + if (sha1Hash != null && sha1Hash.length != 20) + { + throw new IllegalArgumentException("'sha1Hash' must have length == 20, if present"); + } + + this.url = url; + this.sha1Hash = sha1Hash; + } + + public String getURL() + { + return url; + } + + public byte[] getSHA1Hash() + { + return sha1Hash; + } + + /** + * Encode this {@link URLAndHash} to an {@link OutputStream}. + * + * @param output the {@link OutputStream} to encode to. + * @throws IOException + */ + public void encode(OutputStream output) + throws IOException + { + byte[] urlEncoding = Strings.toByteArray(this.url); + TlsUtils.writeOpaque16(urlEncoding, output); + + if (this.sha1Hash == null) + { + TlsUtils.writeUint8(0, output); + } + else + { + TlsUtils.writeUint8(1, output); + output.write(this.sha1Hash); + } + } + + /** + * Parse a {@link URLAndHash} from an {@link InputStream}. + * + * @param context + * the {@link TlsContext} of the current connection. + * @param input + * the {@link InputStream} to parse from. + * @return a {@link URLAndHash} object. + * @throws IOException + */ + public static URLAndHash parse(TlsContext context, InputStream input) + throws IOException + { + byte[] urlEncoding = TlsUtils.readOpaque16(input); + if (urlEncoding.length < 1) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + String url = Strings.fromByteArray(urlEncoding); + + byte[] sha1Hash = null; + short padding = TlsUtils.readUint8(input); + switch (padding) + { + case 0: + if (TlsUtils.isTLSv12(context)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + break; + case 1: + sha1Hash = TlsUtils.readFully(20, input); + break; + default: + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + return new URLAndHash(url, sha1Hash); + } +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/UserMappingType.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/UserMappingType.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/UserMappingType.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/UserMappingType.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,12 @@ +package org.bouncycastle.tls; + +/** + * RFC 4681 + */ +public class UserMappingType +{ + /* + * RFC 4681 + */ + public static final short upn_domain_hint = 64; +} diff -Nru bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/UseSRTPData.java bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/UseSRTPData.java --- bouncycastle-1.55/tls/src/main/java/org/bouncycastle/tls/UseSRTPData.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/java/org/bouncycastle/tls/UseSRTPData.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,52 @@ +package org.bouncycastle.tls; + +/** + * RFC 5764 4.1.1 + */ +public class UseSRTPData +{ + protected int[] protectionProfiles; + protected byte[] mki; + + /** + * @param protectionProfiles see {@link SRTPProtectionProfile} for valid constants. + * @param mki valid lengths from 0 to 255. + */ + public UseSRTPData(int[] protectionProfiles, byte[] mki) + { + if (protectionProfiles == null || protectionProfiles.length < 1 + || protectionProfiles.length >= (1 << 15)) + { + throw new IllegalArgumentException( + "'protectionProfiles' must have length from 1 to (2^15 - 1)"); + } + + if (mki == null) + { + mki = TlsUtils.EMPTY_BYTES; + } + else if (mki.length > 255) + { + throw new IllegalArgumentException("'mki' cannot be longer than 255 bytes"); + } + + this.protectionProfiles = protectionProfiles; + this.mki = mki; + } + + /** + * @return see {@link SRTPProtectionProfile} for valid constants. + */ + public int[] getProtectionProfiles() + { + return protectionProfiles; + } + + /** + * @return valid lengths from 0 to 255. + */ + public byte[] getMki() + { + return mki; + } +} diff -Nru bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/jsse/provider/package.html bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/jsse/provider/package.html --- bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/jsse/provider/package.html 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/jsse/provider/package.html 2016-10-03 23:23:20.000000000 +0000 @@ -0,0 +1,5 @@ + + +The BCJSSE Provider code. + + diff -Nru bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/bc/package.html bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/bc/package.html --- bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/bc/package.html 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/bc/package.html 2016-10-03 23:24:53.000000000 +0000 @@ -0,0 +1,5 @@ + + +Service classes written to support the APIs using the BC light-weight API. + + diff -Nru bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/jcajce/package.html bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/jcajce/package.html --- bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/jcajce/package.html 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/jcajce/package.html 2016-10-03 23:25:31.000000000 +0000 @@ -0,0 +1,5 @@ + + +Service classes written to support the APIs using the JCA and the JCE. + + diff -Nru bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/jcajce/srp/package.html bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/jcajce/srp/package.html --- bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/jcajce/srp/package.html 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/jcajce/srp/package.html 2016-11-22 03:22:39.000000000 +0000 @@ -0,0 +1,5 @@ + + +Service classes written to support SRP-6a using the JCA and the JCE. + + diff -Nru bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/package.html bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/package.html --- bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/package.html 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/crypto/impl/package.html 2016-10-05 03:49:44.000000000 +0000 @@ -0,0 +1,5 @@ + + +Common classes used to support the JCA/JCE and BC light weight services. + + diff -Nru bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/crypto/package.html bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/crypto/package.html --- bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/crypto/package.html 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/crypto/package.html 2016-10-03 23:23:00.000000000 +0000 @@ -0,0 +1,5 @@ + + +Definitions for the cryptography service layer supporting the APIs. + + diff -Nru bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/package.html bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/package.html --- bouncycastle-1.55/tls/src/main/javadoc/org/bouncycastle/tls/package.html 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/javadoc/org/bouncycastle/tls/package.html 2016-10-03 23:21:49.000000000 +0000 @@ -0,0 +1,5 @@ + + +A low-level TLS/DTLS API. + + diff -Nru bouncycastle-1.55/tls/src/main/jdk1.1/org/bouncycastle/tls/UDPTransport.java bouncycastle-1.56/tls/src/main/jdk1.1/org/bouncycastle/tls/UDPTransport.java --- bouncycastle-1.55/tls/src/main/jdk1.1/org/bouncycastle/tls/UDPTransport.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/jdk1.1/org/bouncycastle/tls/UDPTransport.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,106 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; + +public class UDPTransport + implements DatagramTransport +{ + protected final static int MIN_IP_OVERHEAD = 20; + protected final static int MAX_IP_OVERHEAD = MIN_IP_OVERHEAD + 64; + protected final static int UDP_OVERHEAD = 8; + + protected final DatagramSocket socket; + protected final int receiveLimit, sendLimit; + + public UDPTransport(DatagramSocket socket, int mtu) + throws IOException + { + // + // In 1.3 and earlier sockets were bound and connected during creation + // + //if (!socket.isBound() || !socket.isConnected()) + //{ + // throw new IllegalArgumentException("'socket' must be bound and connected"); + //} + + this.socket = socket; + + // NOTE: As of JDK 1.6, can use NetworkInterface.getMTU + + this.receiveLimit = mtu - MIN_IP_OVERHEAD - UDP_OVERHEAD; + this.sendLimit = mtu - MAX_IP_OVERHEAD - UDP_OVERHEAD; + } + + public int getReceiveLimit() + { + return receiveLimit; + } + + public int getSendLimit() + { + // TODO[DTLS] Implement Path-MTU discovery? + return sendLimit; + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + socket.setSoTimeout(waitMillis); + + if (off == 0) + { + DatagramPacket packet = new DatagramPacket(buf, len); + socket.receive(packet); + + return packet.getLength(); + } + else + { + byte[] rv = new byte[len]; + + DatagramPacket packet = new DatagramPacket(rv, len); + socket.receive(packet); + + System.arraycopy(rv, 0, buf, off, packet.getLength()); + + return packet.getLength(); + } + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + if (len > getSendLimit()) + { + /* + * RFC 4347 4.1.1. "If the application attempts to send a record larger than the MTU, + * the DTLS implementation SHOULD generate an error, thus avoiding sending a packet + * which will be fragmented." + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + if (off == 0) + { + DatagramPacket packet = new DatagramPacket(buf, len); + socket.send(packet); + } + else + { + byte[] data = new byte[len]; + + System.arraycopy(buf, off, data, 0, len); + + DatagramPacket packet = new DatagramPacket(data, len); + socket.send(packet); + } + } + + public void close() + throws IOException + { + socket.close(); + } +} diff -Nru bouncycastle-1.55/tls/src/main/jdk1.3/org/bouncycastle/tls/UDPTransport.java bouncycastle-1.56/tls/src/main/jdk1.3/org/bouncycastle/tls/UDPTransport.java --- bouncycastle-1.55/tls/src/main/jdk1.3/org/bouncycastle/tls/UDPTransport.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/main/jdk1.3/org/bouncycastle/tls/UDPTransport.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,78 @@ +package org.bouncycastle.tls; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; + +public class UDPTransport + implements DatagramTransport +{ + protected final static int MIN_IP_OVERHEAD = 20; + protected final static int MAX_IP_OVERHEAD = MIN_IP_OVERHEAD + 64; + protected final static int UDP_OVERHEAD = 8; + + protected final DatagramSocket socket; + protected final int receiveLimit, sendLimit; + + public UDPTransport(DatagramSocket socket, int mtu) + throws IOException + { + // + // In 1.3 and earlier sockets were bound and connected during creation + // + //if (!socket.isBound() || !socket.isConnected()) + //{ + // throw new IllegalArgumentException("'socket' must be bound and connected"); + //} + + this.socket = socket; + + // NOTE: As of JDK 1.6, can use NetworkInterface.getMTU + + this.receiveLimit = mtu - MIN_IP_OVERHEAD - UDP_OVERHEAD; + this.sendLimit = mtu - MAX_IP_OVERHEAD - UDP_OVERHEAD; + } + + public int getReceiveLimit() + { + return receiveLimit; + } + + public int getSendLimit() + { + // TODO[DTLS] Implement Path-MTU discovery? + return sendLimit; + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + socket.setSoTimeout(waitMillis); + DatagramPacket packet = new DatagramPacket(buf, off, len); + socket.receive(packet); + return packet.getLength(); + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + if (len > getSendLimit()) + { + /* + * RFC 4347 4.1.1. "If the application attempts to send a record larger than the MTU, + * the DTLS implementation SHOULD generate an error, thus avoiding sending a packet + * which will be fragmented." + */ + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + DatagramPacket packet = new DatagramPacket(buf, off, len); + socket.send(packet); + } + + public void close() + throws IOException + { + socket.close(); + } +} Binary files /tmp/tmpowJLLf/jkZ0WCu6hH/bouncycastle-1.55/tls/src/test/data/tls/keystores/client_store.dsa and /tmp/tmpowJLLf/lAtENdT3zU/bouncycastle-1.56/tls/src/test/data/tls/keystores/client_store.dsa differ Binary files /tmp/tmpowJLLf/jkZ0WCu6hH/bouncycastle-1.55/tls/src/test/data/tls/keystores/client_store.rsa and /tmp/tmpowJLLf/lAtENdT3zU/bouncycastle-1.56/tls/src/test/data/tls/keystores/client_store.rsa differ Binary files /tmp/tmpowJLLf/jkZ0WCu6hH/bouncycastle-1.55/tls/src/test/data/tls/keystores/server_store.dsa and /tmp/tmpowJLLf/lAtENdT3zU/bouncycastle-1.56/tls/src/test/data/tls/keystores/server_store.dsa differ Binary files /tmp/tmpowJLLf/jkZ0WCu6hH/bouncycastle-1.55/tls/src/test/data/tls/keystores/server_store.rsa and /tmp/tmpowJLLf/lAtENdT3zU/bouncycastle-1.56/tls/src/test/data/tls/keystores/server_store.rsa differ diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/AllTests.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/AllTests.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/AllTests.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/AllTests.java 2016-11-28 09:01:16.000000000 +0000 @@ -0,0 +1,49 @@ +package org.bouncycastle.jsse.provider.test; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class AllTests + extends TestCase +{ + public static void main(String[] args) + throws Exception + { + junit.textui.TestRunner.run(suite()); + } + + public static Test suite() + throws Exception + { + TestSuite suite = new TestSuite("JSSE tests"); + + suite.addTestSuite(BasicClientAuthTlsTest.class); + suite.addTestSuite(BasicTlsTest.class); + suite.addTestSuite(ConfigTest.class); + suite.addTestSuite(InstanceTest.class); + suite.addTestSuite(KeyManagerFactoryTest.class); + + return new BCTestSetup(suite); + } + + static class BCTestSetup + extends TestSetup + { + public BCTestSetup(Test test) + { + super(test); + } + + protected void setUp() + { + + } + + protected void tearDown() + { + + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicClientAuthTlsTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicClientAuthTlsTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicClientAuthTlsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicClientAuthTlsTest.java 2016-11-28 09:01:16.000000000 +0000 @@ -0,0 +1,201 @@ +package org.bouncycastle.jsse.provider.test; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.concurrent.CountDownLatch; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManagerFactory; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; + +import junit.framework.TestCase; + +public class BasicClientAuthTlsTest + extends TestCase +{ + protected void setUp() + { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + if (Security.getProvider(BouncyCastleJsseProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastleJsseProvider()); + } + } + + private static final String HOST = "localhost"; + private static final int PORT_NO = 9020; + + public static class ClientAuthClient + implements TestProtocolUtil.BlockingCallable + { + private final KeyStore trustStore; + private final KeyStore clientStore; + private final char[] clientKeyPass; + private final CountDownLatch latch; + + public ClientAuthClient(KeyStore clientStore, char[] clientKeyPass, X509Certificate trustAnchor) + throws GeneralSecurityException, IOException + { + this.trustStore = KeyStore.getInstance("JKS"); + + trustStore.load(null, null); + + trustStore.setCertificateEntry("server", trustAnchor); + + this.clientStore = clientStore; + this.clientKeyPass = clientKeyPass; + this.latch = new CountDownLatch(1); + } + + public Object call() + throws Exception + { + TrustManagerFactory trustMgrFact = TrustManagerFactory.getInstance("X509", + BouncyCastleJsseProvider.PROVIDER_NAME); + + trustMgrFact.init(trustStore); + + KeyManagerFactory keyMgrFact = KeyManagerFactory.getInstance("PKIX", + BouncyCastleJsseProvider.PROVIDER_NAME); + + keyMgrFact.init(clientStore, clientKeyPass); + + SSLContext clientContext = SSLContext.getInstance("TLS", BouncyCastleJsseProvider.PROVIDER_NAME); + + clientContext.init(keyMgrFact.getKeyManagers(), trustMgrFact.getTrustManagers(), + SecureRandom.getInstance("DEFAULT", BouncyCastleProvider.PROVIDER_NAME)); + + SSLSocketFactory fact = clientContext.getSocketFactory(); + SSLSocket cSock = (SSLSocket)fact.createSocket(HOST, PORT_NO); + + SSLUtils.restrictKeyExchange(cSock, "ECDHE_ECDSA"); + + SSLSession session = cSock.getSession(); + + assertEquals("CN=Test CA Certificate", session.getLocalPrincipal().getName()); + assertEquals("CN=Test CA Certificate", session.getPeerPrincipal().getName()); + + TestProtocolUtil.doClientProtocol(cSock, "Hello"); + + latch.countDown(); + + return null; + } + + public void await() + throws InterruptedException + { + latch.await(); + } + } + + public static class ClientAuthServer + implements TestProtocolUtil.BlockingCallable + { + private final KeyStore serverStore; + private final char[] keyPass; + private final KeyStore trustStore; + private final CountDownLatch latch; + + ClientAuthServer(KeyStore serverStore, char[] keyPass, X509Certificate trustAnchor) + throws GeneralSecurityException, IOException + { + this.serverStore = serverStore; + this.keyPass = keyPass; + this.trustStore = KeyStore.getInstance("JKS"); + + trustStore.load(null, null); + + trustStore.setCertificateEntry("client", trustAnchor); + + this.latch = new CountDownLatch(1); + } + + public Object call() + throws Exception + { + KeyManagerFactory keyMgrFact = KeyManagerFactory.getInstance("X509", + BouncyCastleJsseProvider.PROVIDER_NAME); + + keyMgrFact.init(serverStore, keyPass); + + TrustManagerFactory trustMgrFact = TrustManagerFactory.getInstance("PKIX", + BouncyCastleJsseProvider.PROVIDER_NAME); + + trustMgrFact.init(trustStore); + + SSLContext serverContext = SSLContext.getInstance("TLS", BouncyCastleJsseProvider.PROVIDER_NAME); + + serverContext.init(keyMgrFact.getKeyManagers(), trustMgrFact.getTrustManagers(), + SecureRandom.getInstance("DEFAULT", BouncyCastleProvider.PROVIDER_NAME)); + + SSLServerSocketFactory fact = serverContext.getServerSocketFactory(); + SSLServerSocket sSock = (SSLServerSocket)fact.createServerSocket(PORT_NO); + + SSLUtils.enableAll(sSock); + + sSock.setNeedClientAuth(true); + + latch.countDown(); + + SSLSocket sslSock = (SSLSocket)sSock.accept(); + + SSLSession session = sslSock.getSession(); + + assertEquals("CN=Test CA Certificate", session.getLocalPrincipal().getName()); + assertEquals("CN=Test CA Certificate", session.getPeerPrincipal().getName()); + + TestProtocolUtil.doServerProtocol(sslSock, "World"); + + sslSock.close(); + + return null; + } + + public void await() + throws InterruptedException + { + latch.await(); + } + } + + public void testClientAuthTlsConnection() + throws Exception + { + char[] keyPass = "keyPassword".toCharArray(); + + KeyPair caKeyPair = TestUtils.generateECKeyPair();; + + X509Certificate caCert = TestUtils.generateRootCert(caKeyPair); + + KeyStore serverKs = KeyStore.getInstance("JKS"); + + serverKs.load(null, null); + + serverKs.setKeyEntry("server", caKeyPair.getPrivate(), keyPass, new X509Certificate[]{ caCert }); + + KeyStore clientKs = KeyStore.getInstance("JKS"); + + clientKs.load(null, null); + + clientKs.setKeyEntry("client", caKeyPair.getPrivate(), keyPass, new X509Certificate[]{ caCert }); + + TestProtocolUtil.runClientAndServer(new ClientAuthServer(serverKs, keyPass, caCert), new ClientAuthClient(serverKs, keyPass, caCert)); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java 2016-12-01 22:54:27.000000000 +0000 @@ -0,0 +1,152 @@ +package org.bouncycastle.jsse.provider.test; + +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.concurrent.CountDownLatch; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManagerFactory; + +import junit.framework.TestCase; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; + +public class BasicTlsTest + extends TestCase +{ + protected void setUp() + { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + if (Security.getProvider(BouncyCastleJsseProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastleJsseProvider()); + } + } + + private static final String HOST = "localhost"; + private static final int PORT_NO = 9021; + + public static class SimpleClient + implements TestProtocolUtil.BlockingCallable + { + private final KeyStore trustStore; + private final CountDownLatch latch; + + public SimpleClient(KeyStore trustStore) + { + this.trustStore = trustStore; + this.latch = new CountDownLatch(1); + } + + public Object call() + throws Exception + { + TrustManagerFactory trustMgrFact = TrustManagerFactory.getInstance("X509", + BouncyCastleJsseProvider.PROVIDER_NAME); + + trustMgrFact.init(trustStore); + + SSLContext clientContext = SSLContext.getInstance("TLS", BouncyCastleJsseProvider.PROVIDER_NAME); + + clientContext.init(null, trustMgrFact.getTrustManagers(), + SecureRandom.getInstance("DEFAULT", BouncyCastleProvider.PROVIDER_NAME)); + + SSLSocketFactory fact = clientContext.getSocketFactory(); + SSLSocket cSock = (SSLSocket)fact.createSocket(HOST, PORT_NO); + + SSLUtils.restrictKeyExchange(cSock, "ECDHE_ECDSA"); + + TestProtocolUtil.doClientProtocol(cSock, "Hello"); + + latch.countDown(); + + return null; + } + + public void await() + throws InterruptedException + { + latch.await(); + } + } + + public static class SimpleServer + implements TestProtocolUtil.BlockingCallable + { + private final KeyStore serverStore; + private final char[] keyPass; + private final CountDownLatch latch; + + SimpleServer(KeyStore serverStore, char[] keyPass) + { + this.serverStore = serverStore; + this.keyPass = keyPass; + this.latch = new CountDownLatch(1); + } + + public Object call() + throws Exception + { + KeyManagerFactory keyMgrFact = KeyManagerFactory.getInstance("X509", + BouncyCastleJsseProvider.PROVIDER_NAME); + + keyMgrFact.init(serverStore, keyPass); + + SSLContext serverContext = SSLContext.getInstance("TLS", BouncyCastleJsseProvider.PROVIDER_NAME); + + serverContext.init(keyMgrFact.getKeyManagers(), null, + SecureRandom.getInstance("DEFAULT", BouncyCastleProvider.PROVIDER_NAME)); + + SSLServerSocketFactory fact = serverContext.getServerSocketFactory(); + SSLServerSocket sSock = (SSLServerSocket)fact.createServerSocket(PORT_NO); + + SSLUtils.enableAll(sSock); + + latch.countDown(); + + SSLSocket sslSock = (SSLSocket)sSock.accept(); + sslSock.setUseClientMode(false); + + TestProtocolUtil.doServerProtocol(sslSock, "World"); + + return null; + } + + public void await() + throws InterruptedException + { + latch.await(); + } + } + + public void testBasicTlsConnection() + throws Exception + { + char[] keyPass = "keyPassword".toCharArray(); + + KeyPair caKeyPair = TestUtils.generateECKeyPair(); + + X509Certificate caCert = TestUtils.generateRootCert(caKeyPair); + + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(null, null); + ks.setKeyEntry("server", caKeyPair.getPrivate(), keyPass, new X509Certificate[]{ caCert }); + + KeyStore ts = KeyStore.getInstance("JKS"); + ts.load(null, null); + ts.setCertificateEntry("ca", caCert); + + TestProtocolUtil.runClientAndServer(new SimpleServer(ks, keyPass), new SimpleClient(ts)); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/ConfigTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/ConfigTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/ConfigTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/ConfigTest.java 2016-11-28 09:01:16.000000000 +0000 @@ -0,0 +1,48 @@ +package org.bouncycastle.jsse.provider.test; + + +import java.security.Security; + +import junit.framework.TestCase; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; + +public class ConfigTest + extends TestCase +{ + protected void setUp() + { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + } + + public void testWithString() + { + String BC = BouncyCastleProvider.PROVIDER_NAME; + + BouncyCastleJsseProvider jsseProv = new BouncyCastleJsseProvider("fips:" + BC); + + assertTrue(jsseProv.isFipsMode()); + + jsseProv = new BouncyCastleJsseProvider(BC); + + assertFalse(jsseProv.isFipsMode()); + + jsseProv = new BouncyCastleJsseProvider("unknown:" + BC); + + assertFalse(jsseProv.isFipsMode()); + } + + public void testWithProvider() + { + BouncyCastleJsseProvider jsseProv = new BouncyCastleJsseProvider(true, new BouncyCastleProvider()); + + assertTrue(jsseProv.isFipsMode()); + + jsseProv = new BouncyCastleJsseProvider(new BouncyCastleProvider()); + + assertFalse(jsseProv.isFipsMode()); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/InstanceTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/InstanceTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/InstanceTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/InstanceTest.java 2016-10-25 05:52:36.000000000 +0000 @@ -0,0 +1,42 @@ +package org.bouncycastle.jsse.provider.test; + +import java.security.Security; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; + +import junit.framework.TestCase; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; + +public class InstanceTest + extends TestCase +{ + protected void setUp() + { + Security.addProvider(new BouncyCastleJsseProvider()); + } + + protected void tearDown() + { + Security.removeProvider(BouncyCastleJsseProvider.PROVIDER_NAME); + } + + public void testKeyManager() + throws Exception + { + KeyManagerFactory.getInstance("PKIX", BouncyCastleJsseProvider.PROVIDER_NAME); + } + + public void testTrustManager() + throws Exception + { + TrustManagerFactory.getInstance("PKIX", BouncyCastleJsseProvider.PROVIDER_NAME); + } + + public void testSSLContext() + throws Exception + { + SSLContext.getInstance("TLS", BouncyCastleJsseProvider.PROVIDER_NAME); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/KeyManagerFactoryTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/KeyManagerFactoryTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/KeyManagerFactoryTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/KeyManagerFactoryTest.java 2016-12-09 23:02:14.000000000 +0000 @@ -0,0 +1,240 @@ +package org.bouncycastle.jsse.provider.test; + +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.Principal; +import java.security.Security; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509ExtendedKeyManager; +import javax.security.auth.x500.X500Principal; + +import junit.framework.TestCase; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; + +public class KeyManagerFactoryTest + extends TestCase +{ + + private static final char[] PASSWORD = "fred".toCharArray(); + + protected void setUp() + { + Security.addProvider(new BouncyCastleProvider()); + Security.addProvider(new BouncyCastleJsseProvider()); + } + + protected void tearDown() + { + Security.removeProvider(BouncyCastleJsseProvider.PROVIDER_NAME); + } + + public void testBasicRSA() + throws Exception + { + KeyManagerFactory fact = KeyManagerFactory.getInstance("PKIX", BouncyCastleJsseProvider.PROVIDER_NAME); + + KeyStore ks = getRsaKeyStore(true); + + fact.init(ks, PASSWORD); + + KeyManager[] managers = fact.getKeyManagers(); + + X509ExtendedKeyManager manager = (X509ExtendedKeyManager)managers[0]; + + String alias = manager.chooseServerAlias("RSA", null, null); + + assertNotNull(alias); + + assertNotNull(manager.getCertificateChain(alias)); + + assertNotNull(manager.getPrivateKey(alias)); + + alias = manager.chooseServerAlias("RSA", new Principal[] { new X500Principal("CN=TLS Test") }, null); + + assertNull(alias); + + alias = manager.chooseServerAlias("RSA", new Principal[] { new X500Principal("CN=TLS Test CA") }, null); + + assertNotNull(alias); + + assertNotNull(manager.getCertificateChain(alias)); + + assertNotNull(manager.getPrivateKey(alias)); + } + + public void testBasicEC() + throws Exception + { + KeyManagerFactory fact = KeyManagerFactory.getInstance("PKIX", BouncyCastleJsseProvider.PROVIDER_NAME); + + KeyStore ks = getEcKeyStore(false); + + fact.init(ks, PASSWORD); + + KeyManager[] managers = fact.getKeyManagers(); + + X509ExtendedKeyManager manager = (X509ExtendedKeyManager)managers[0]; + + String alias = manager.chooseServerAlias("ECDHE_ECDSA", null, null); + + assertNotNull(alias); + + assertNotNull(manager.getCertificateChain(alias)); + + assertNotNull(manager.getPrivateKey(alias)); + + alias = manager.chooseServerAlias("ECDHE_ECDSA", new Principal[] { new X500Principal("CN=TLS Test") }, null); + + assertNull(alias); + + alias = manager.chooseServerAlias("ECDHE_ECDSA", new Principal[] { new X500Principal("CN=TLS Test CA") }, null); + + assertNotNull(alias); + + assertNotNull(manager.getCertificateChain(alias)); + + assertNotNull(manager.getPrivateKey(alias)); + } + + private KeyStore getRsaKeyStore(boolean encryption) + throws Exception + { + KeyStore ks = KeyStore.getInstance("JKS"); + + KeyPair rPair = TestUtils.generateRSAKeyPair(); + KeyPair iPair = TestUtils.generateRSAKeyPair(); + KeyPair ePair = TestUtils.generateRSAKeyPair(); + + X509Certificate rCert = TestUtils.generateRootCert(rPair); + X509Certificate iCert = TestUtils.generateIntermediateCert(iPair.getPublic(), new X500Name("CN=TLS Test CA"), rPair.getPrivate(), rCert); + + X509Certificate eCert; + if (encryption) + { + eCert = TestUtils.generateEndEntityCertEnc(ePair.getPublic(), new X500Name("CN=TLS Test"), iPair.getPrivate(), iCert); + } + else + { + eCert = TestUtils.generateEndEntityCertSign(ePair.getPublic(), new X500Name("CN=TLS Test"), iPair.getPrivate(), iCert); + } + + ks.load(null, PASSWORD); + + ks.setKeyEntry("test", ePair.getPrivate(), PASSWORD, new Certificate[] { eCert, iCert }); + + ks.setCertificateEntry("root", rCert); + + return ks; + } + + private KeyStore getEcKeyStore(boolean agreement) + throws Exception + { + KeyStore ks = KeyStore.getInstance("JKS"); + + KeyPair rPair = TestUtils.generateECKeyPair(); + KeyPair iPair = TestUtils.generateECKeyPair(); + KeyPair ePair = TestUtils.generateECKeyPair(); + + X509Certificate rCert = TestUtils.generateRootCert(rPair); + X509Certificate iCert = TestUtils.generateIntermediateCert(iPair.getPublic(), new X500Name("CN=TLS Test CA"), rPair.getPrivate(), rCert); + + X509Certificate eCert; + if (agreement) + { + eCert = TestUtils.generateEndEntityCertAgree(ePair.getPublic(), new X500Name("CN=TLS Test"), iPair.getPrivate(), iCert); + } + else + { + eCert = TestUtils.generateEndEntityCertSign(ePair.getPublic(), new X500Name("CN=TLS Test"), iPair.getPrivate(), iCert); + } + + ks.load(null, PASSWORD); + + ks.setKeyEntry("test", ePair.getPrivate(), PASSWORD, new Certificate[] { eCert, iCert }); + + ks.setCertificateEntry("root", rCert); + + return ks; + } + + public void testRSAServer() + throws Exception + { + KeyStore ks = getRsaKeyStore(false); + + KeyStore trustStore = KeyStore.getInstance("JKS"); + + trustStore.load(null, PASSWORD); + + trustStore.setCertificateEntry("server", ks.getCertificate("root")); + + SSLUtils.startServer(ks, PASSWORD, trustStore, false, 8886); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX", BouncyCastleJsseProvider.PROVIDER_NAME); + + trustManagerFactory.init(trustStore); + + SSLContext context = SSLContext.getInstance("TLS"); + + context.init(null, trustManagerFactory.getTrustManagers(), null); + + SSLSocketFactory f = context.getSocketFactory(); + + SSLSocket c = (SSLSocket)f.createSocket("localhost", 8886); + c.setUseClientMode(true); + + c.getOutputStream().write('!'); + + c.getInputStream().read(); + + } + + public void testRSAServerWithClientAuth() + throws Exception + { + KeyStore ks = getRsaKeyStore(false); + + KeyStore trustStore = KeyStore.getInstance("JKS"); + + trustStore.load(null, PASSWORD); + + trustStore.setCertificateEntry("server", ks.getCertificate("root")); + + SSLUtils.startServer(ks, PASSWORD, trustStore, true, 8887); + + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX", BouncyCastleJsseProvider.PROVIDER_NAME); + + keyManagerFactory.init(ks, PASSWORD); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX", BouncyCastleJsseProvider.PROVIDER_NAME); + + trustManagerFactory.init(trustStore); + + SSLContext context = SSLContext.getInstance("TLS"); + + context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); + + SSLSocketFactory f = context.getSocketFactory(); + + SSLSocket c = (SSLSocket)f.createSocket("localhost", 8887); + c.setUseClientMode(true); + + SSLUtils.restrictKeyExchange(c, "RSA"); // 1.5 compatibility + + c.getOutputStream().write('!'); + + c.getInputStream().read(); + + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/SSLUtils.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/SSLUtils.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/SSLUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/SSLUtils.java 2016-12-10 07:15:22.000000000 +0000 @@ -0,0 +1,123 @@ +package org.bouncycastle.jsse.provider.test; + +import java.security.KeyStore; +import java.security.Security; +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManagerFactory; + +class SSLUtils +{ + static void enableAll(SSLServerSocket ss) + { + ss.setEnabledCipherSuites(ss.getSupportedCipherSuites()); + ss.setEnabledProtocols(ss.getEnabledProtocols()); + } + + static void restrictKeyExchange(SSLSocket s, String keyExchange) + { + ArrayList enabled = new ArrayList(); + for (String suite : s.getSupportedCipherSuites()) + { + if (suite.startsWith("TLS_" + keyExchange + "_WITH")) + { + enabled.add(suite); + } + } + // some JSSE don't use TLS_ + if (enabled.isEmpty()) + { + for (String suite : s.getSupportedCipherSuites()) + { + if (suite.startsWith("SSL_" + keyExchange + "_WITH")) + { + enabled.add(suite); + } + } + } + s.setEnabledCipherSuites(enabled.toArray(new String[enabled.size()])); + } + + static void startServer(final KeyStore keyStore, final char[] password, final KeyStore serverStore) + { + startServer(keyStore, password, serverStore, false, 8888); + } + + static void startServer(final KeyStore keyStore, final char[] password, final KeyStore serverStore, final boolean needClientAuth, + final int port) + { + final CountDownLatch latch = new CountDownLatch(1); + + Runnable serverTask = new Runnable() + { + public void run() + { + try + { + KeyManagerFactory keyManagerFactory; + + if (Security.getProvider("IBMJSSE2") != null) + { + keyManagerFactory = KeyManagerFactory.getInstance("IBMX509"); + } + else + { + keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); + } + + keyManagerFactory.init(keyStore, password); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX"); + + trustManagerFactory.init(serverStore); + + SSLContext context = SSLContext.getInstance("TLS"); + + context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); + + SSLServerSocketFactory sslSocketFactory = context.getServerSocketFactory(); + + SSLServerSocket ss = (SSLServerSocket)sslSocketFactory.createServerSocket(port); + + enableAll(ss); + + ss.setNeedClientAuth(needClientAuth); + + latch.countDown(); + + SSLSocket s = (SSLSocket)ss.accept(); + s.setUseClientMode(false); + + s.getInputStream().read(); + + s.getOutputStream().write('!'); + + s.close(); + + ss.close(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + }; + + new Thread(serverTask).start(); + + try + { + latch.await(); + } + catch (InterruptedException e) + { + + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestProtocolUtil.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestProtocolUtil.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestProtocolUtil.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestProtocolUtil.java 2016-09-30 00:33:59.000000000 +0000 @@ -0,0 +1,106 @@ +package org.bouncycastle.jsse.provider.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.concurrent.Callable; + +import junit.framework.Assert; +import org.bouncycastle.util.Strings; + +class TestProtocolUtil +{ + public interface BlockingCallable + extends Callable + { + void await() throws InterruptedException; + } + + public static class Task + implements Runnable + { + private final Callable callable; + + public Task(Callable callable) + { + this.callable = callable; + } + + public void run() + { + try + { + callable.call(); + } + catch (Exception e) + { + e.printStackTrace(System.err); + if (e.getCause() != null) + { + e.getCause().printStackTrace(System.err); + } + } + } + } + + public static void runClientAndServer(BlockingCallable server, BlockingCallable client) + throws InterruptedException + { + new Thread(new TestProtocolUtil.Task(server)).start(); + server.await(); + + new Thread(new TestProtocolUtil.Task(client)).start(); + client.await(); + } + + public static void doClientProtocol( + Socket sock, + String text) + throws IOException + { + OutputStream out = sock.getOutputStream(); + InputStream in = sock.getInputStream(); + + writeMessage(text, out); + + String message = readMessage(in); + + Assert.assertEquals("World", message); + } + + public static void doServerProtocol( + Socket sock, + String text) + throws IOException + { + OutputStream out = sock.getOutputStream(); + InputStream in = sock.getInputStream(); + + String message = readMessage(in); + + writeMessage(text, out); + + Assert.assertEquals("Hello", message); + } + + private static void writeMessage(String text, OutputStream out) + throws IOException + { + out.write(Strings.toByteArray(text)); + out.write('!'); + } + + private static String readMessage(InputStream in) + throws IOException + { + StringBuilder sb = new StringBuilder(); + + int ch; + while ((ch = in.read()) != '!') + { + sb.append((char)ch); + } + return sb.toString(); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestUtils.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestUtils.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestUtils.java 2016-11-28 09:01:16.000000000 +0000 @@ -0,0 +1,480 @@ +package org.bouncycastle.jsse.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.ExtensionsGenerator; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.asn1.x509.TBSCertificate; +import org.bouncycastle.asn1.x509.Time; +import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator; +import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; +import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +/** + * Test Utils + */ +class TestUtils +{ + private static AtomicLong serialNumber = new AtomicLong(System.currentTimeMillis()); + private static Map algIds = new HashMap(); + + static + { + algIds.put("GOST3411withGOST3410", new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94)); + algIds.put("SHA1withRSA", new AlgorithmIdentifier(PKCSObjectIdentifiers.sha1WithRSAEncryption, DERNull.INSTANCE)); + algIds.put("SHA256withRSA", new AlgorithmIdentifier(PKCSObjectIdentifiers.sha256WithRSAEncryption, DERNull.INSTANCE)); + algIds.put("SHA256withECDSA", new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256)); + } + + public static X509Certificate createSelfSignedCert(String dn, String sigName, KeyPair keyPair) + throws Exception + { + return createSelfSignedCert(new X500Name(dn), sigName, keyPair); + } + + public static X509Certificate createSelfSignedCert(X500Name dn, String sigName, KeyPair keyPair) + throws Exception + { + V1TBSCertificateGenerator certGen = new V1TBSCertificateGenerator(); + + long time = System.currentTimeMillis(); + + certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement())); + certGen.setIssuer(dn); + certGen.setSubject(dn); + certGen.setStartDate(new Time(new Date(time - 5000))); + certGen.setEndDate(new Time(new Date(time + 30 * 60 * 1000))); + certGen.setSignature((AlgorithmIdentifier)algIds.get(sigName)); + certGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded())); + + Signature sig = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME); + + sig.initSign(keyPair.getPrivate()); + + sig.update(certGen.generateTBSCertificate().getEncoded(ASN1Encoding.DER)); + + TBSCertificate tbsCert = certGen.generateTBSCertificate(); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCert); + v.add((AlgorithmIdentifier)algIds.get(sigName)); + v.add(new DERBitString(sig.sign())); + + return (X509Certificate)CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME) + .generateCertificate(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER))); + } + + public static X509Certificate createCert(X500Name signerName, PrivateKey signerKey, String dn, String sigName, Extensions extensions, PublicKey pubKey) + throws Exception + { + return createCert(signerName, signerKey, new X500Name(dn), sigName, extensions, pubKey); + } + + public static X509Certificate createCert(X500Name signerName, PrivateKey signerKey, X500Name dn, String sigName, Extensions extensions, PublicKey pubKey) + throws Exception + { + V3TBSCertificateGenerator certGen = new V3TBSCertificateGenerator(); + + long time = System.currentTimeMillis(); + + certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement())); + certGen.setIssuer(signerName); + certGen.setSubject(dn); + certGen.setStartDate(new Time(new Date(time - 5000))); + certGen.setEndDate(new Time(new Date(time + 30 * 60 * 1000))); + certGen.setSignature((AlgorithmIdentifier)algIds.get(sigName)); + certGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded())); + certGen.setExtensions(extensions); + + Signature sig = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME); + + sig.initSign(signerKey); + + sig.update(certGen.generateTBSCertificate().getEncoded(ASN1Encoding.DER)); + + TBSCertificate tbsCert = certGen.generateTBSCertificate(); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCert); + v.add((AlgorithmIdentifier)algIds.get(sigName)); + v.add(new DERBitString(sig.sign())); + + return (X509Certificate)CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME) + .generateCertificate(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER))); + } + + /** + * Create a random 1024 bit RSA key pair + */ + public static KeyPair generateRSAKeyPair() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME); + + kpGen.initialize(1024, new SecureRandom()); + + return kpGen.generateKeyPair(); + } + + public static KeyPair generateECKeyPair() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); + + kpGen.initialize(256, new SecureRandom()); + + return kpGen.generateKeyPair(); + } + + public static X509Certificate generateRootCert(KeyPair pair) + throws Exception + { + if (pair.getPublic().getAlgorithm().equals("RSA")) + { + return createSelfSignedCert("CN=Test CA Certificate", "SHA256withRSA", pair); + } + else + { + return createSelfSignedCert("CN=Test CA Certificate", "SHA256withECDSA", pair); + } + } + + public static X509Certificate generateRootCert(KeyPair pair, X500Name dn) + throws Exception + { + return createSelfSignedCert(dn, "SHA256withRSA", pair); + } + + public static X509Certificate generateIntermediateCert(PublicKey intKey, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + return generateIntermediateCert( + intKey, new X500Name("CN=Test Intermediate Certificate"), caKey, caCert); + } + + public static X509Certificate generateIntermediateCert(PublicKey intKey, X500Name subject, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + Certificate caCertLw = Certificate.getInstance(caCert.getEncoded()); + + ExtensionsGenerator extGen = new ExtensionsGenerator(); + + extGen.addExtension(Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifier(getDigest(caCertLw.getSubjectPublicKeyInfo()), + new GeneralNames(new GeneralName(caCertLw.getIssuer())), + caCertLw.getSerialNumber().getValue())); + extGen.addExtension(Extension.subjectKeyIdentifier, false, new SubjectKeyIdentifier(getDigest(SubjectPublicKeyInfo.getInstance(intKey.getEncoded())))); + extGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0)); + extGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); + + if (intKey.getAlgorithm().equals("RSA")) + { + return createCert( + caCertLw.getSubject(), + caKey, subject, "SHA256withRSA", extGen.generate(), intKey); + } + else + { + return createCert( + caCertLw.getSubject(), + caKey, subject, "SHA256withECDSA", extGen.generate(), intKey); + } + } + + public static X509Certificate generateEndEntityCertAgree(PublicKey intKey, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + return generateEndEntityCertAgree(intKey, new X500Name("CN=Test End Certificate"), caKey, caCert); + } + + public static X509Certificate generateEndEntityCertEnc(PublicKey intKey, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + return generateEndEntityCertEnc(intKey, new X500Name("CN=Test End Certificate"), caKey, caCert); + } + + public static X509Certificate generateEndEntityCertSign(PublicKey intKey, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + return generateEndEntityCertSign(intKey, new X500Name("CN=Test End Certificate"), caKey, caCert); + } + + public static X509Certificate generateEndEntityCertAgree(PublicKey entityKey, X500Name subject, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + return generateEndEntityCert(entityKey, subject, KeyUsage.keyAgreement, caKey, caCert); + } + + public static X509Certificate generateEndEntityCertEnc(PublicKey entityKey, X500Name subject, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + return generateEndEntityCert(entityKey, subject, KeyUsage.keyEncipherment, caKey, caCert); + } + + public static X509Certificate generateEndEntityCertSign(PublicKey entityKey, X500Name subject, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + return generateEndEntityCert(entityKey, subject, KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign, caKey, caCert); + } + + public static X509Certificate generateEndEntityCert(PublicKey entityKey, X500Name subject, int keyUsage, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + Certificate caCertLw = Certificate.getInstance(caCert.getEncoded()); + + ExtensionsGenerator extGen = new ExtensionsGenerator(); + + extGen.addExtension(Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifier(getDigest(caCertLw.getSubjectPublicKeyInfo()), + new GeneralNames(new GeneralName(caCertLw.getIssuer())), + caCertLw.getSerialNumber().getValue())); + extGen.addExtension(Extension.subjectKeyIdentifier, false, new SubjectKeyIdentifier(getDigest(entityKey.getEncoded()))); + extGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0)); +// extGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); + extGen.addExtension(Extension.keyUsage, true, new KeyUsage(keyUsage)); + + if (entityKey.getAlgorithm().equals("RSA")) + { + return createCert( + caCertLw.getSubject(), + caKey, subject, "SHA256withRSA", extGen.generate(), entityKey); + } + else + { + return createCert( + caCertLw.getSubject(), + caKey, subject, "SHA256withECDSA", extGen.generate(), entityKey); + } + } + + public static X509Certificate createExceptionCertificate(boolean exceptionOnEncode) + { + return new ExceptionCertificate(exceptionOnEncode); + } + + private static class ExceptionCertificate + extends X509Certificate + { + private boolean _exceptionOnEncode; + + public ExceptionCertificate(boolean exceptionOnEncode) + { + _exceptionOnEncode = exceptionOnEncode; + } + + public void checkValidity() + throws CertificateExpiredException, CertificateNotYetValidException + { + throw new CertificateNotYetValidException(); + } + + public void checkValidity(Date date) + throws CertificateExpiredException, CertificateNotYetValidException + { + throw new CertificateExpiredException(); + } + + public int getVersion() + { + return 0; + } + + public BigInteger getSerialNumber() + { + return null; + } + + public Principal getIssuerDN() + { + return null; + } + + public Principal getSubjectDN() + { + return null; + } + + public Date getNotBefore() + { + return null; + } + + public Date getNotAfter() + { + return null; + } + + public byte[] getTBSCertificate() + throws CertificateEncodingException + { + throw new CertificateEncodingException(); + } + + public byte[] getSignature() + { + return new byte[0]; + } + + public String getSigAlgName() + { + return null; + } + + public String getSigAlgOID() + { + return null; + } + + public byte[] getSigAlgParams() + { + return new byte[0]; + } + + public boolean[] getIssuerUniqueID() + { + return new boolean[0]; + } + + public boolean[] getSubjectUniqueID() + { + return new boolean[0]; + } + + public boolean[] getKeyUsage() + { + return new boolean[0]; + } + + public int getBasicConstraints() + { + return 0; + } + + public byte[] getEncoded() + throws CertificateEncodingException + { + if (_exceptionOnEncode) + { + throw new CertificateEncodingException(); + } + + return new byte[0]; + } + + public void verify(PublicKey key) + throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException + { + throw new CertificateException(); + } + + public void verify(PublicKey key, String sigProvider) + throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException + { + throw new CertificateException(); + } + + public String toString() + { + return null; + } + + public PublicKey getPublicKey() + { + return null; + } + + public boolean hasUnsupportedCriticalExtension() + { + return false; + } + + public Set getCriticalExtensionOIDs() + { + return null; + } + + public Set getNonCriticalExtensionOIDs() + { + return null; + } + + public byte[] getExtensionValue(String oid) + { + return new byte[0]; + } + + } + + private static byte[] getDigest(SubjectPublicKeyInfo spki) + throws IOException, NoSuchAlgorithmException + { + return getDigest(spki.getPublicKeyData().getBytes()); + } + + private static byte[] getDigest(byte[] bytes) + throws IOException, NoSuchAlgorithmException + { + MessageDigest calc = MessageDigest.getInstance("SHA1"); + + return calc.digest(bytes); + } + + private static class AtomicLong + { + private long value; + + public AtomicLong(long value) + { + this.value = value; + } + + public synchronized long getAndIncrement() + { + return value++; + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java 2016-11-18 03:44:17.000000000 +0000 @@ -0,0 +1,52 @@ +package org.bouncycastle.tls.test; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class AllTests + extends TestCase +{ + public static void main(String[] args) + throws Exception + { + junit.textui.TestRunner.run(suite()); + } + + public static Test suite() + throws Exception + { + TestSuite suite = new TestSuite("TLS tests"); + + suite.addTestSuite(BasicTlsTest.class); + suite.addTestSuite(DTLSProtocolTest.class); + suite.addTestSuite(DTLSTestCase.class); + suite.addTestSuite(TlsProtocolTest.class); + suite.addTestSuite(TlsPSKProtocolTest.class); + suite.addTestSuite(TlsSRPProtocolTest.class); + suite.addTestSuite(TlsTestCase.class); + suite.addTest(TlsTestSuite.suite()); + + return new BCTestSetup(suite); + } + + static class BCTestSetup + extends TestSetup + { + public BCTestSetup(Test test) + { + super(test); + } + + protected void setUp() + { + + } + + protected void tearDown() + { + + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/BasicTlsTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/BasicTlsTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/BasicTlsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/BasicTlsTest.java 2016-11-21 00:44:31.000000000 +0000 @@ -0,0 +1,299 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.net.Socket; +import java.security.SecureRandom; + +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.CipherSuite; +import org.bouncycastle.tls.DefaultTlsClient; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SecurityParameters; +import org.bouncycastle.tls.ServerOnlyTlsAuthentication; +import org.bouncycastle.tls.TlsAuthentication; +import org.bouncycastle.tls.TlsClient; +import org.bouncycastle.tls.TlsClientContext; +import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsKeyExchange; +import org.bouncycastle.tls.TlsSession; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + +public class BasicTlsTest + extends TestCase +{ + private static final int PORT_NO = 12001; + + protected boolean isSufficientVMVersion(String vmVersion) + { + if (vmVersion == null) + { + return false; + } + String[] parts = vmVersion.split("\\."); + if (parts == null || parts.length != 2) + { + return false; + } + try + { + int major = Integer.parseInt(parts[0]); + if (major != 1) + { + return major > 1; + } + int minor = Integer.parseInt(parts[1]); + return minor >= 7; + } + catch (NumberFormatException e) + { + return false; + } + } + + public void testConnection() + throws Exception + { + String vmVersion = System.getProperty("java.specification.version"); + if (!isSufficientVMVersion(vmVersion)) + { + return; // only works on later VMs. + } + + Thread server = new HTTPSServerThread(); + + server.start(); + + Thread.yield(); + + Socket s = null; + + for (int i = 0; s == null && i != 3; i++) + { + Thread.sleep(1000); + + try + { + s = new Socket("localhost", PORT_NO); + } + catch (IOException e) + { + // ignore + } + } + + if (s == null) + { + throw new IOException("unable to connect"); + } + + TlsClientProtocol protocol = new TlsClientProtocol(s.getInputStream(), s.getOutputStream()); + protocol.connect(new MyTlsClient(new ServerOnlyTlsAuthentication() + { + public void notifyServerCertificate(Certificate serverCertificate) throws IOException + { + // NOTE: In production code this MUST verify the certificate! + } + })); + + InputStream is = protocol.getInputStream(); + OutputStream os = protocol.getOutputStream(); + + os.write("GET / HTTP/1.1\r\n\r\n".getBytes()); + + byte[] buf = new byte[4096]; + int read = 0; + int total = 0; + + while ((read = is.read(buf, total, buf.length - total)) > 0) + { + total += read; + } + + is.close(); + + byte[] expected = Hex.decode("485454502f312e3120323030204f4b0d0a436f6e74656e742d547970653a20746578742f68" + + "746d6c0d0a0d0a3c68746d6c3e0d0a3c626f64793e0d0a48656c6c6f20576f726c64210d0a3c2f626f64793e0d0a3c2f" + + "68746d6c3e0d0a"); + assertEquals(total, expected.length); + + byte[] tmp = new byte[expected.length]; + System.arraycopy(buf, 0, tmp, 0, total); + assertTrue(Arrays.areEqual(expected, tmp)); + } + + public void testRSAConnectionClient() + throws Exception + { + MyTlsClient client = new MyTlsClient(null); + + checkConnectionClient(client, CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA, TlsTestUtils.rsaCertData); + checkConnectionClient(client, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, TlsTestUtils.rsaCertData); + checkConnectionClient(client, CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, TlsTestUtils.rsaCertData); + checkConnectionClient(client, CipherSuite.TLS_RSA_WITH_RC4_128_SHA, TlsTestUtils.rsaCertData); + + try + { + checkConnectionClient(client, CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA, TlsTestUtils.dudRsaCertData); + + fail("dud certificate not caught"); + } + catch (TlsFatalAlert e) + { + assertEquals(AlertDescription.certificate_unknown, e.getAlertDescription()); + } + + try + { + checkConnectionClient(client, CipherSuite.TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, TlsTestUtils.rsaCertData); + + fail("wrong certificate not caught"); + } + catch (TlsFatalAlert e) + { + assertEquals(AlertDescription.internal_error, e.getAlertDescription()); + } + } + + private void checkConnectionClient(TlsClient client, int cipherSuite, byte[] encCert) + throws Exception + { + TlsCrypto crypto = client.getCrypto(); + + client.notifySelectedCipherSuite(cipherSuite); + + TlsKeyExchange keyExchange = client.getKeyExchange(); + keyExchange.init(new MyTlsClientContext(crypto)); + + keyExchange + .processServerCertificate(new Certificate( + new TlsCertificate[]{ crypto.createCertificate(encCert) })); + } + + public static TestSuite suite() + { + return new TestSuite(BasicTlsTest.class); + } + + public static void main(String[] args) + throws Exception + { + junit.textui.TestRunner.run(suite()); + } + + static class MyTlsClient + extends DefaultTlsClient + { + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS client raised alert: " + AlertLevel.getText(alertLevel) + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println(message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS client received alert: " + AlertLevel.getText(alertLevel) + ", " + AlertDescription.getText(alertDescription)); + } + + private final TlsAuthentication authentication; + + MyTlsClient(TlsAuthentication authentication) + { + super(new BcTlsCrypto(new SecureRandom())); + + this.authentication = authentication; + } + + public TlsAuthentication getAuthentication() + throws IOException + { + return authentication; + } + } + + static class MyTlsClientContext + implements TlsClientContext + { + TlsCrypto crypto; + + MyTlsClientContext(TlsCrypto crypto) + { + this.crypto = crypto; + } + + public TlsCrypto getCrypto() + { + return crypto; + } + + public SecureRandom getSecureRandom() + { + throw new UnsupportedOperationException(); + } + + public SecurityParameters getSecurityParameters() + { + throw new UnsupportedOperationException(); + } + + public boolean isServer() + { + return false; + } + + public ProtocolVersion getClientVersion() + { + return ProtocolVersion.TLSv12; + } + + public ProtocolVersion getServerVersion() + { + return ProtocolVersion.TLSv12; + } + + public TlsSession getResumableSession() + { + return null; + } + + public TlsSession getSession() + { + return null; + } + + public Object getUserObject() + { + throw new UnsupportedOperationException(); + } + + public void setUserObject(Object userObject) + { + throw new UnsupportedOperationException(); + } + + public byte[] exportKeyingMaterial(String asciiLabel, byte[] context_value, int length) + { + throw new UnsupportedOperationException(); + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/ByteQueueInputStreamTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/ByteQueueInputStreamTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/ByteQueueInputStreamTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/ByteQueueInputStreamTest.java 2016-10-25 06:04:03.000000000 +0000 @@ -0,0 +1,126 @@ +package org.bouncycastle.tls.test; + +import junit.framework.TestCase; +import org.bouncycastle.tls.ByteQueueInputStream; +import org.bouncycastle.util.Arrays; + +public class ByteQueueInputStreamTest + extends TestCase +{ + public void testAvailable() + { + ByteQueueInputStream in = new ByteQueueInputStream(); + + // buffer is empty + assertEquals(0, in.available()); + + // after adding once + in.addBytes(new byte[10]); + assertEquals(10, in.available()); + + // after adding more than once + in.addBytes(new byte[5]); + assertEquals(15, in.available()); + + // after reading a single byte + in.read(); + assertEquals(14, in.available()); + + // after reading into a byte array + in.read(new byte[4]); + assertEquals(10, in.available()); + + in.close();// so Eclipse doesn't whine about a resource leak + } + + public void testSkip() + { + ByteQueueInputStream in = new ByteQueueInputStream(); + + // skip when buffer is empty + assertEquals(0, in.skip(10)); + + // skip equal to available + in.addBytes(new byte[2]); + assertEquals(2, in.skip(2)); + assertEquals(0, in.available()); + + // skip less than available + in.addBytes(new byte[10]); + assertEquals(5, in.skip(5)); + assertEquals(5, in.available()); + + // skip more than available + assertEquals(5, in.skip(20)); + assertEquals(0, in.available()); + + in.close();// so Eclipse doesn't whine about a resource leak + } + + public void testRead() + { + ByteQueueInputStream in = new ByteQueueInputStream(); + in.addBytes(new byte[]{ 0x01, 0x02 }); + in.addBytes(new byte[]{ 0x03 }); + + assertEquals(0x01, in.read()); + assertEquals(0x02, in.read()); + assertEquals(0x03, in.read()); + assertEquals(-1, in.read()); + + in.close();// so Eclipse doesn't whine about a resource leak + } + + public void testReadArray() + { + ByteQueueInputStream in = new ByteQueueInputStream(); + in.addBytes(new byte[]{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }); + + byte[] buffer = new byte[5]; + + // read less than available into specified position + assertEquals(1, in.read(buffer, 2, 1)); + assertArrayEquals(new byte[]{ 0x00, 0x00, 0x01, 0x00, 0x00 }, buffer); + + // read equal to available + assertEquals(5, in.read(buffer)); + assertArrayEquals(new byte[]{ 0x02, 0x03, 0x04, 0x05, 0x06 }, buffer); + + // read more than available + in.addBytes(new byte[]{ 0x01, 0x02, 0x03 }); + assertEquals(3, in.read(buffer)); + assertArrayEquals(new byte[]{ 0x01, 0x02, 0x03, 0x05, 0x06 }, buffer); + + in.close();// so Eclipse doesn't whine about a resource leak + } + + public void testPeek() + { + ByteQueueInputStream in = new ByteQueueInputStream(); + + byte[] buffer = new byte[5]; + + // peek more than available + assertEquals(0, in.peek(buffer)); + assertArrayEquals(new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00 }, buffer); + + // peek less than available + in.addBytes(new byte[]{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }); + assertEquals(5, in.peek(buffer)); + assertArrayEquals(new byte[]{ 0x01, 0x02, 0x03, 0x04, 0x05 }, buffer); + assertEquals(6, in.available()); + + // peek equal to available + in.read(); + assertEquals(5, in.peek(buffer)); + assertArrayEquals(new byte[]{ 0x02, 0x03, 0x04, 0x05, 0x06 }, buffer); + assertEquals(5, in.available()); + + in.close();// so Eclipse doesn't whine about a resource leak + } + + private static void assertArrayEquals(byte[] a, byte[] b) + { + assertTrue(Arrays.areEqual(a, b)); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSClientTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSClientTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSClientTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSClientTest.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,81 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.security.SecureRandom; + +import org.bouncycastle.tls.DTLSClientProtocol; +import org.bouncycastle.tls.DTLSTransport; +import org.bouncycastle.tls.DatagramTransport; +import org.bouncycastle.tls.TlsClient; +import org.bouncycastle.tls.TlsSession; +import org.bouncycastle.tls.UDPTransport; + +/** + * A simple test designed to conduct a DTLS handshake with an external DTLS server. + *

      + * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external DTLS server. + *

      + */ +public class DTLSClientTest +{ + private static final SecureRandom secureRandom = new SecureRandom(); + + public static void main(String[] args) + throws Exception + { + InetAddress address = InetAddress.getLocalHost(); + int port = 5556; + + TlsSession session = createSession(address, port); + + MockDTLSClient client = new MockDTLSClient(session); + + DTLSTransport dtls = openDTLSConnection(address, port, client); + + System.out.println("Receive limit: " + dtls.getReceiveLimit()); + System.out.println("Send limit: " + dtls.getSendLimit()); + + // Send and hopefully receive a packet back + + byte[] request = "Hello World!\n".getBytes("UTF-8"); + dtls.send(request, 0, request.length); + + byte[] response = new byte[dtls.getReceiveLimit()]; + int received = dtls.receive(response, 0, response.length, 30000); + if (received >= 0) + { + System.out.println(new String(response, 0, received, "UTF-8")); + } + + dtls.close(); + } + + private static TlsSession createSession(InetAddress address, int port) + throws IOException + { + MockDTLSClient client = new MockDTLSClient(null); + DTLSTransport dtls = openDTLSConnection(address, port, client); + TlsSession session = client.getSessionToResume(); + dtls.close(); + return session; + } + + private static DTLSTransport openDTLSConnection(InetAddress address, int port, TlsClient client) + throws IOException + { + DatagramSocket socket = new DatagramSocket(); + socket.connect(address, port); + + int mtu = 1500; + DatagramTransport transport = new UDPTransport(socket, mtu); + transport = new UnreliableDatagramTransport(transport, secureRandom, 0, 0); + transport = new LoggingDatagramTransport(transport, System.out); + + DTLSClientProtocol protocol = new DTLSClientProtocol(secureRandom); + + return protocol.connect(client, transport); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSProtocolTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSProtocolTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSProtocolTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSProtocolTest.java 2016-10-25 06:04:03.000000000 +0000 @@ -0,0 +1,101 @@ +package org.bouncycastle.tls.test; + +import java.security.SecureRandom; + +import junit.framework.TestCase; +import org.bouncycastle.tls.DTLSClientProtocol; +import org.bouncycastle.tls.DTLSServerProtocol; +import org.bouncycastle.tls.DTLSTransport; +import org.bouncycastle.tls.DatagramTransport; +import org.bouncycastle.util.Arrays; + +public class DTLSProtocolTest + extends TestCase +{ + public void testClientServer() + throws Exception + { + SecureRandom secureRandom = new SecureRandom(); + + DTLSClientProtocol clientProtocol = new DTLSClientProtocol(secureRandom); + DTLSServerProtocol serverProtocol = new DTLSServerProtocol(secureRandom); + + MockDatagramAssociation network = new MockDatagramAssociation(1500); + + ServerThread serverThread = new ServerThread(serverProtocol, network.getServer()); + serverThread.start(); + + DatagramTransport clientTransport = network.getClient(); + + clientTransport = new UnreliableDatagramTransport(clientTransport, secureRandom, 0, 0); + + clientTransport = new LoggingDatagramTransport(clientTransport, System.out); + + MockDTLSClient client = new MockDTLSClient(null); + + DTLSTransport dtlsClient = clientProtocol.connect(client, clientTransport); + + for (int i = 1; i <= 10; ++i) + { + byte[] data = new byte[i]; + Arrays.fill(data, (byte)i); + dtlsClient.send(data, 0, data.length); + } + + byte[] buf = new byte[dtlsClient.getReceiveLimit()]; + while (dtlsClient.receive(buf, 0, buf.length, 100) >= 0) + { + } + + dtlsClient.close(); + + serverThread.shutdown(); + } + + static class ServerThread + extends Thread + { + private final DTLSServerProtocol serverProtocol; + private final DatagramTransport serverTransport; + private volatile boolean isShutdown = false; + + ServerThread(DTLSServerProtocol serverProtocol, DatagramTransport serverTransport) + { + this.serverProtocol = serverProtocol; + this.serverTransport = serverTransport; + } + + public void run() + { + try + { + MockDTLSServer server = new MockDTLSServer(); + DTLSTransport dtlsServer = serverProtocol.accept(server, serverTransport); + byte[] buf = new byte[dtlsServer.getReceiveLimit()]; + while (!isShutdown) + { + int length = dtlsServer.receive(buf, 0, buf.length, 1000); + if (length >= 0) + { + dtlsServer.send(buf, 0, length); + } + } + dtlsServer.close(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + void shutdown() + throws InterruptedException + { + if (!isShutdown) + { + isShutdown = true; + this.join(); + } + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSServerTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSServerTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSServerTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSServerTest.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,75 @@ +package org.bouncycastle.tls.test; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.SocketTimeoutException; +import java.security.SecureRandom; + +import org.bouncycastle.tls.DTLSServerProtocol; +import org.bouncycastle.tls.DTLSTransport; +import org.bouncycastle.tls.DatagramTransport; +import org.bouncycastle.tls.UDPTransport; + +/** + * A simple test designed to conduct a DTLS handshake with an external DTLS client. + *

      + * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external DTLS client. + *

      + */ +public class DTLSServerTest +{ + public static void main(String[] args) + throws Exception + { + int port = 5556; + + int mtu = 1500; + + SecureRandom secureRandom = new SecureRandom(); + + DTLSServerProtocol serverProtocol = new DTLSServerProtocol(secureRandom); + + byte[] data = new byte[mtu]; + DatagramPacket packet = new DatagramPacket(data, mtu); + + DatagramSocket socket = new DatagramSocket(port); + socket.receive(packet); + + System.out.println("Accepting connection from " + packet.getAddress().getHostAddress() + ":" + port); + socket.connect(packet.getAddress(), packet.getPort()); + + /* + * NOTE: For simplicity, and since we don't yet have HelloVerifyRequest support, we just + * discard the initial packet, which the client should re-send anyway. + */ + + DatagramTransport transport = new UDPTransport(socket, mtu); + + // Uncomment to see packets +// transport = new LoggingDatagramTransport(transport, System.out); + + MockDTLSServer server = new MockDTLSServer(); + DTLSTransport dtlsServer = serverProtocol.accept(server, transport); + + byte[] buf = new byte[dtlsServer.getReceiveLimit()]; + + while (!socket.isClosed()) + { + try + { + int length = dtlsServer.receive(buf, 0, buf.length, 60000); + if (length >= 0) + { + System.out.write(buf, 0, length); + dtlsServer.send(buf, 0, length); + } + } + catch (SocketTimeoutException ste) + { + } + } + + dtlsServer.close(); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestCase.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestCase.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestCase.java 2016-10-25 06:04:03.000000000 +0000 @@ -0,0 +1,176 @@ +package org.bouncycastle.tls.test; + +import java.security.SecureRandom; + +import junit.framework.TestCase; +import org.bouncycastle.tls.DTLSTransport; +import org.bouncycastle.tls.DatagramTransport; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.util.Arrays; + +public class DTLSTestCase extends TestCase +{ + private static void checkDTLSVersion(ProtocolVersion version) + { + if (version != null && !version.isDTLS()) + { + throw new IllegalStateException("Non-DTLS version"); + } + } + + protected final TlsTestConfig config; + + public DTLSTestCase(String name) + { + super(name); + + this.config = null; + } + + public DTLSTestCase(TlsTestConfig config, String name) + { + super(name); + + checkDTLSVersion(config.clientMinimumVersion); + checkDTLSVersion(config.clientOfferVersion); + checkDTLSVersion(config.serverMaximumVersion); + checkDTLSVersion(config.serverMinimumVersion); + + this.config = config; + } + + public void testDummy() + { + // Avoid "No tests found" warning from junit + } + + protected void runTest() throws Throwable + { + // Disable the test if it is not being run via DTLSTestSuite + if (config == null) + { + return; + } + + SecureRandom secureRandom = new SecureRandom(); + + DTLSTestClientProtocol clientProtocol = new DTLSTestClientProtocol(secureRandom, config); + DTLSTestServerProtocol serverProtocol = new DTLSTestServerProtocol(secureRandom, config); + + MockDatagramAssociation network = new MockDatagramAssociation(1500); + + TlsTestClientImpl clientImpl = new TlsTestClientImpl(config); + TlsTestServerImpl serverImpl = new TlsTestServerImpl(config); + + ServerThread serverThread = new ServerThread(serverProtocol, network.getServer(), serverImpl); + serverThread.start(); + + Exception caught = null; + try + { + DatagramTransport clientTransport = network.getClient(); + + if (TlsTestConfig.DEBUG) + { + clientTransport = new LoggingDatagramTransport(clientTransport, System.out); + } + + DTLSTransport dtlsClient = clientProtocol.connect(clientImpl, clientTransport); + + for (int i = 1; i <= 10; ++i) + { + byte[] data = new byte[i]; + Arrays.fill(data, (byte)i); + dtlsClient.send(data, 0, data.length); + } + + byte[] buf = new byte[dtlsClient.getReceiveLimit()]; + while (dtlsClient.receive(buf, 0, buf.length, 100) >= 0) + { + } + + dtlsClient.close(); + } + catch (Exception e) + { + caught = e; + logException(caught); + } + + serverThread.shutdown(); + + // TODO Add checks that the various streams were closed + + assertEquals("Client fatal alert connection end", config.expectFatalAlertConnectionEnd, clientImpl.firstFatalAlertConnectionEnd); + assertEquals("Server fatal alert connection end", config.expectFatalAlertConnectionEnd, serverImpl.firstFatalAlertConnectionEnd); + + assertEquals("Client fatal alert description", config.expectFatalAlertDescription, clientImpl.firstFatalAlertDescription); + assertEquals("Server fatal alert description", config.expectFatalAlertDescription, serverImpl.firstFatalAlertDescription); + + if (config.expectFatalAlertConnectionEnd == -1) + { + assertNull("Unexpected client exception", caught); + assertNull("Unexpected server exception", serverThread.caught); + } + } + + protected void logException(Exception e) + { + if (TlsTestConfig.DEBUG) + { + e.printStackTrace(); + } + } + + class ServerThread + extends Thread + { + private final DTLSTestServerProtocol serverProtocol; + private final DatagramTransport serverTransport; + private final TlsTestServerImpl serverImpl; + + private volatile boolean isShutdown = false; + Exception caught = null; + + ServerThread(DTLSTestServerProtocol serverProtocol, DatagramTransport serverTransport, TlsTestServerImpl serverImpl) + { + this.serverProtocol = serverProtocol; + this.serverTransport = serverTransport; + this.serverImpl = serverImpl; + } + + public void run() + { + try + { + DTLSTransport dtlsServer = serverProtocol.accept(serverImpl, serverTransport); + byte[] buf = new byte[dtlsServer.getReceiveLimit()]; + while (!isShutdown) + { + int length = dtlsServer.receive(buf, 0, buf.length, 100); + if (length >= 0) + { + dtlsServer.send(buf, 0, length); + } + } + dtlsServer.close(); + } + catch (Exception e) + { + caught = e; + logException(caught); + } + } + + void shutdown() + throws InterruptedException + { + if (!isShutdown) + { + isShutdown = true; + this.interrupt(); + this.join(); + } + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestClientProtocol.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestClientProtocol.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestClientProtocol.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestClientProtocol.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,30 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.security.SecureRandom; + +import org.bouncycastle.tls.DTLSClientProtocol; +import org.bouncycastle.tls.DigitallySigned; + +class DTLSTestClientProtocol extends DTLSClientProtocol +{ + protected final TlsTestConfig config; + + public DTLSTestClientProtocol(SecureRandom secureRandom, TlsTestConfig config) + { + super(secureRandom); + + this.config = config; + } + + protected byte[] generateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify) + throws IOException + { + if (certificateVerify.getAlgorithm() != null && config.clientAuthSigAlgClaimed != null) + { + certificateVerify = new DigitallySigned(config.clientAuthSigAlgClaimed, certificateVerify.getSignature()); + } + + return super.generateCertificateVerify(state, certificateVerify); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestServerProtocol.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestServerProtocol.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestServerProtocol.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestServerProtocol.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,17 @@ +package org.bouncycastle.tls.test; + +import java.security.SecureRandom; + +import org.bouncycastle.tls.DTLSServerProtocol; + +class DTLSTestServerProtocol extends DTLSServerProtocol +{ + protected final TlsTestConfig config; + + public DTLSTestServerProtocol(SecureRandom secureRandom, TlsTestConfig config) + { + super(secureRandom); + + this.config = config; + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestSuite.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestSuite.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestSuite.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestSuite.java 2016-10-25 06:04:03.000000000 +0000 @@ -0,0 +1,210 @@ +package org.bouncycastle.tls.test; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.bouncycastle.tls.ProtocolVersion; + +public class DTLSTestSuite extends TestSuite +{ + // Make the access to constants less verbose + static abstract class C extends TlsTestConfig {} + + public DTLSTestSuite() + { + super("DTLS"); + } + + public static Test suite() + { + DTLSTestSuite testSuite = new DTLSTestSuite(); + + addFallbackTests(testSuite); + addVersionTests(testSuite, ProtocolVersion.DTLSv10); + addVersionTests(testSuite, ProtocolVersion.DTLSv12); + + return testSuite; + } + + private static void addFallbackTests(TestSuite testSuite) + { + { + TlsTestConfig c = createDTLSTestConfig(ProtocolVersion.DTLSv12); + c.clientFallback = true; + + addTestCase(testSuite, c, "FallbackGood"); + } + + /* + * NOTE: Temporarily disabled automatic test runs because of problems getting a clean exit + * of the DTLS server after a fatal alert. As of writing, manual runs show the correct + * alerts being raised + */ + +// { +// TlsTestConfig c = createDTLSTestConfig(ProtocolVersion.DTLSv12); +// c.clientOfferVersion = ProtocolVersion.DTLSv10; +// c.clientFallback = true; +// c.expectServerFatalAlert(AlertDescription.inappropriate_fallback); +// +// addTestCase(testSuite, c, "FallbackBad"); +// } + + { + TlsTestConfig c = createDTLSTestConfig(ProtocolVersion.DTLSv12); + c.clientOfferVersion = ProtocolVersion.DTLSv10; + + addTestCase(testSuite, c, "FallbackNone"); + } + } + + private static void addVersionTests(TestSuite testSuite, ProtocolVersion version) + { + String prefix = version.toString().replaceAll("[ \\.]", "") + "_"; + + /* + * NOTE: Temporarily disabled automatic test runs because of problems getting a clean exit + * of the DTLS server after a fatal alert. As of writing, manual runs show the correct + * alerts being raised + */ + +// /* +// * Server only declares support for SHA1/RSA, client selects MD5/RSA. Since the client is +// * NOT actually tracking MD5 over the handshake, we expect fatal alert from the client. +// */ +// if (TlsUtils.isTLSv12(version)) +// { +// TlsTestConfig c = createDTLSTestConfig(version); +// c.clientAuth = C.CLIENT_AUTH_VALID; +// c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.md5, SignatureAlgorithm.rsa); +// c.serverCertReqSigAlgs = TlsUtils.getDefaultRSASignatureAlgorithms(); +// c.expectClientFatalAlert(AlertDescription.internal_error); +// +// addTestCase(testSuite, c, prefix + "BadCertificateVerifyHashAlg"); +// } +// +// /* +// * Server only declares support for SHA1/ECDSA, client selects SHA1/RSA. Since the client is +// * actually tracking SHA1 over the handshake, we expect fatal alert to come from the server +// * when it verifies the selected algorithm against the CertificateRequest supported +// * algorithms. +// */ +// if (TlsUtils.isTLSv12(version)) +// { +// TlsTestConfig c = createDTLSTestConfig(version); +// c.clientAuth = C.CLIENT_AUTH_VALID; +// c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa); +// c.serverCertReqSigAlgs = TlsUtils.getDefaultECDSASignatureAlgorithms(); +// c.expectServerFatalAlert(AlertDescription.illegal_parameter); +// +// addTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlg"); +// } +// +// /* +// * Server only declares support for SHA1/ECDSA, client signs with SHA1/RSA, but sends +// * SHA1/ECDSA in the CertificateVerify. Since the client is actually tracking SHA1 over the +// * handshake, and the claimed algorithm is in the CertificateRequest supported algorithms, +// * we expect fatal alert to come from the server when it finds the claimed algorithm +// * doesn't match the client certificate. +// */ +// if (TlsUtils.isTLSv12(version)) +// { +// TlsTestConfig c = createDTLSTestConfig(version); +// c.clientAuth = C.CLIENT_AUTH_VALID; +// c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa); +// c.clientAuthSigAlgClaimed = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa); +// c.serverCertReqSigAlgs = TlsUtils.getDefaultECDSASignatureAlgorithms(); +// c.expectServerFatalAlert(AlertDescription.decrypt_error); +// +// addTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlgMismatch"); +// } +// +// { +// TlsTestConfig c = createDTLSTestConfig(version); +// c.clientAuth = C.CLIENT_AUTH_INVALID_VERIFY; +// c.expectServerFatalAlert(AlertDescription.decrypt_error); +// +// addTestCase(testSuite, c, prefix + "BadCertificateVerifySignature"); +// } +// +// { +// TlsTestConfig c = createDTLSTestConfig(version); +// c.clientAuth = C.CLIENT_AUTH_INVALID_CERT; +// c.expectServerFatalAlert(AlertDescription.bad_certificate); +// +// addTestCase(testSuite, c, prefix + "BadClientCertificate"); +// } +// +// { +// TlsTestConfig c = createDTLSTestConfig(version); +// c.clientAuth = C.CLIENT_AUTH_NONE; +// c.serverCertReq = C.SERVER_CERT_REQ_MANDATORY; +// c.expectServerFatalAlert(AlertDescription.handshake_failure); +// +// addTestCase(testSuite, c, prefix + "BadMandatoryCertReqDeclined"); +// } +// +// /* +// * Server selects MD5/RSA for ServerKeyExchange signature, which is not in the default +// * supported signature algorithms that the client sent. We expect fatal alert from the +// * client when it verifies the selected algorithm against the supported algorithms. +// */ +// if (TlsUtils.isTLSv12(version)) +// { +// TlsTestConfig c = createDTLSTestConfig(version); +// c.serverAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.md5, SignatureAlgorithm.rsa); +// c.expectClientFatalAlert(AlertDescription.illegal_parameter); +// +// addTestCase(testSuite, c, prefix + "BadServerKeyExchangeSigAlg"); +// } +// +// /* +// * Server selects MD5/RSA for ServerKeyExchange signature, which is not the default {sha1,rsa} +// * implied by the absent signature_algorithms extension. We expect fatal alert from the +// * client when it verifies the selected algorithm against the implicit default. +// */ +// if (TlsUtils.isTLSv12(version)) +// { +// TlsTestConfig c = createDTLSTestConfig(version); +// c.clientSendSignatureAlgorithms = false; +// c.serverAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.md5, SignatureAlgorithm.rsa); +// c.expectClientFatalAlert(AlertDescription.illegal_parameter); +// +// addTestCase(testSuite, c, prefix + "BadServerKeyExchangeSigAlg2"); +// } + + { + TlsTestConfig c = createDTLSTestConfig(version); + + addTestCase(testSuite, c, prefix + "GoodDefault"); + } + + { + TlsTestConfig c = createDTLSTestConfig(version); + c.serverCertReq = C.SERVER_CERT_REQ_NONE; + + addTestCase(testSuite, c, prefix + "GoodNoCertReq"); + } + + { + TlsTestConfig c = createDTLSTestConfig(version); + c.clientAuth = C.CLIENT_AUTH_NONE; + + addTestCase(testSuite, c, prefix + "GoodOptionalCertReqDeclined"); + } + } + + private static void addTestCase(TestSuite testSuite, TlsTestConfig config, String name) + { + testSuite.addTest(new DTLSTestCase(config, name)); + } + + private static TlsTestConfig createDTLSTestConfig(ProtocolVersion version) + { + TlsTestConfig c = new TlsTestConfig(); + c.clientMinimumVersion = ProtocolVersion.DTLSv10; + c.clientOfferVersion = ProtocolVersion.DTLSv12; + c.serverMaximumVersion = version; + c.serverMinimumVersion = ProtocolVersion.DTLSv10; + return c; + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/HTTPSServerThread.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/HTTPSServerThread.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/HTTPSServerThread.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/HTTPSServerThread.java 2016-11-28 09:01:16.000000000 +0000 @@ -0,0 +1,112 @@ +package org.bouncycastle.tls.test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.security.KeyStore; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManagerFactory; + +public class HTTPSServerThread + extends Thread +{ + private static final int PORT_NO = 12001; + private static final char[] SERVER_PASSWORD = "serverPassword".toCharArray(); + private static final char[] TRUST_STORE_PASSWORD = "trustPassword".toCharArray(); + + /** + * Read a HTTP request + */ + private void readRequest( + InputStream in) + throws IOException + { + int ch = 0; + int lastCh = 0; + while ((ch = in.read()) >= 0 && (ch != '\n' && lastCh != '\n')) + { + if (ch != '\r') + { + lastCh = ch; + } + } + } + + /** + * Send a response + */ + private void sendResponse( + OutputStream out) + { + PrintWriter pWrt = new PrintWriter(new OutputStreamWriter(out)); + pWrt.print("HTTP/1.1 200 OK\r\n"); + pWrt.print("Content-Type: text/html\r\n"); + pWrt.print("\r\n"); + pWrt.print("\r\n"); + pWrt.print("\r\n"); + pWrt.print("Hello World!\r\n"); + pWrt.print("\r\n"); + pWrt.print("\r\n"); + pWrt.flush(); + } + + SSLContext createSSLContext() + throws Exception + { + KeyManagerFactory mgrFact = KeyManagerFactory.getInstance("SunX509"); + KeyStore serverStore = KeyStore.getInstance("JKS"); + + serverStore.load(new ByteArrayInputStream(KeyStores.server), SERVER_PASSWORD); + + mgrFact.init(serverStore, SERVER_PASSWORD); + + // set up a trust manager so we can recognize the server + TrustManagerFactory trustFact = TrustManagerFactory.getInstance("SunX509"); + KeyStore trustStore = KeyStore.getInstance("JKS"); + + trustStore.load(new ByteArrayInputStream(KeyStores.trustStore), TRUST_STORE_PASSWORD); + + trustFact.init(trustStore); + + // create a context and set up a socket factory + SSLContext sslContext = SSLContext.getInstance("TLS"); + + sslContext.init(mgrFact.getKeyManagers(), trustFact.getTrustManagers(), null); + + return sslContext; + } + + public void run() + { + try + { + SSLContext sslContext = createSSLContext(); + SSLServerSocketFactory fact = sslContext.getServerSocketFactory(); + + SSLServerSocket sSock = (SSLServerSocket)fact.createServerSocket(PORT_NO); + SSLSocket sslSock = (SSLSocket)sSock.accept(); + sslSock.setUseClientMode(false); + + readRequest(sslSock.getInputStream()); + + SSLSession session = sslSock.getSession(); + + sendResponse(sslSock.getOutputStream()); + + sslSock.close(); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/KeyStores.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/KeyStores.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/KeyStores.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/KeyStores.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,113 @@ +package org.bouncycastle.tls.test; + +import org.bouncycastle.util.encoders.Base64; + +public class KeyStores +{ + static final byte[] trustStore = Base64.decode( + "/u3+7QAAAAIAAAABAAAAAgAGc2VydmVyAAABD34zDJEABVguNTA5AAABrzCC" + + "AaswggEUAgEBMA0GCSqGSIb3DQEBBQUAMB4xHDAaBgNVBAMTE1Rlc3QgQ0Eg" + + "Q2VydGlmaWNhdGUwHhcNMDYxMjEzMjM0MzI5WhcNMDYxMjIwMjM0MzI5WjAe" + + "MRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEB" + + "AQUAA4GNADCBiQKBgQCmOumCM46ehsdcrZMw6tj0hMl5D0xf21gcyBj/ByIv" + + "pe008ukaN3zCXIUUUlAu0GkbI1sCbTD1V4qVZuaHqtfa/FINJjyZJy5w7KEx" + + "93OOF2/gyPlnEPGs6RPdThAPliSBsWKBKqtOdmKpwYn/NKuUNFRkFXVLLUPn" + + "jyEKjIcNywIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACi8J7raYqDFjXqAXXPJ" + + "ljZHqvzJNVaSWvBtK/oY7g0+sdGIjPR526fhSCxOZRr7G157ERqMnPjuFjcm" + + "cRlUOPsQtTl6KbUnxmKxa04UzDuNXzSx2oyGx5GCWx9u62hpO6vSpK69L9gH" + + "OUtM5dQXcoK4i3olScKaU8qaYb0mBAy8fnx5pen8B0bIg+pz47l5VxQ5NO8="); + + static final byte[] server = Base64.decode( + "/u3+7QAAAAIAAAABAAAAAQAGc2VydmVyAAABD34zDJIAAAK8MIICuDAOBgor" + + "BgEEASoCEQEBBQAEggKk9OXWj3aBr6rV9Grcsm2YL+/2ShVsxbJVGMSWll1f" + + "U8z/mjhv5K/skgleTIMoyE5FzDDxJIGEmSMCkcHsnseXzxyhLpKBaz3N1Tk7" + + "KVPzXfrNh0FJwzw3lPWyC2ayT+ObQfAtzuI9SUWNLBzzpWeolUJ8gkXnLshX" + + "5RqmR735NRZdjgQOtNYBBErX/NOhTyi009/CZDNxgJQzywFmQcXBLhNSA+0i" + + "cE+LwZ4sZV0NXshPZiyNnsfqN/XNOyhpKr8a3VyVtee2nhO9+FY5IDEviHmR" + + "WDvH5TmB6Os3L6xvwE1ZQCPElk/cK2G1q9+zDBe4JDeo8o7lPhiNpVfcivnr" + + "+tyK9m7PqlssR0+ohuZGwrFMyzLugkOWh+qZ3pk8/7AwJosMvvTvIg36nN7R" + + "pdnouQNKqTm1Sr/UUnKyWqfG7zqKIuF72IkDwwafwuQ9YRX5PAOuRfo6bCyb" + + "D4w1OWdfGFciKMc1BrT+8JzhiTkzNe+jWEA5Tw1zeazPGpp1RHPz2np50G2s" + + "v025uiOSUilBe13Qpx0mAyx7z8Gl6eOxai6rQ/eB/Fu++BMx0OX8vO/K4//Q" + + "w43IPVPklGlb/3Qt7eoNf4tichuxrYJjHu4XbwnzB29Vmsan0XZFER7epvFj" + + "cAZCSG+O6G/f6Ib+7d7xYjLdUaPI60tJ4/C+AuYwZn4jJwTnMnMmwIypz4Z8" + + "XPXW5SbHlV5OkkFC+eAuuN4b2YXZmifeWv4fx65Ioir921LMJrorMizH41RJ" + + "/rAO5wGSwjeDJ784QhhLGbEUMygraRtdaz6MRx26InnoHY7V58ET3Z5YGV39" + + "p+9AtVhYw/QQmTZiF7hqnEMf9AMVFfac9qFF2+IN3g9HAMC6QLxJ1VuPn5oo" + + "lS//axPfjckO7iZx9x59/gAAAAEABVguNTA5AAABrzCCAaswggEUAgEBMA0G" + + "CSqGSIb3DQEBBQUAMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGUw" + + "HhcNMDYxMjEzMjM0MzI5WhcNMDYxMjIwMjM0MzI5WjAeMRwwGgYDVQQDExNU" + + "ZXN0IENBIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB" + + "gQCmOumCM46ehsdcrZMw6tj0hMl5D0xf21gcyBj/ByIvpe008ukaN3zCXIUU" + + "UlAu0GkbI1sCbTD1V4qVZuaHqtfa/FINJjyZJy5w7KEx93OOF2/gyPlnEPGs" + + "6RPdThAPliSBsWKBKqtOdmKpwYn/NKuUNFRkFXVLLUPnjyEKjIcNywIDAQAB" + + "MA0GCSqGSIb3DQEBBQUAA4GBACi8J7raYqDFjXqAXXPJljZHqvzJNVaSWvBt" + + "K/oY7g0+sdGIjPR526fhSCxOZRr7G157ERqMnPjuFjcmcRlUOPsQtTl6KbUn" + + "xmKxa04UzDuNXzSx2oyGx5GCWx9u62hpO6vSpK69L9gHOUtM5dQXcoK4i3ol" + + "ScKaU8qaYb0mBAy87VQaPfaiQqqxSgqifbSowlg+0fg="); + + static final byte[] client = Base64.decode( + "MIACAQMwgAYJKoZIhvcNAQcBoIAkgASCA+gwgDCABgkqhkiG9w0BBwGggCSA" + + "BIIDDzCCAwswggMHBgsqhkiG9w0BDAoBAqCCArIwggKuMCgGCiqGSIb3DQEM" + + "AQMwGgQUyeN8U+ViAJCk1WGo8wTnRVOaE1oCAgQABIICgH3yMWB+dfMBNa07" + + "hn3smUSBTF+LUauM+kx+12nZt0QazBYg09yM+aVcTznettlDwE/PTpKZnrFT" + + "22DSQf5GwABwiL6KW+xyM8wV5vZx1xtqrQoNf2oNHnF0lB7ddSYM8jHqennb" + + "bzcVOdrrCqewqAfUU/CDugpwwI8c8Iy9ECri6vBMbfeIIZQTug+1952TCCiA" + + "E1bEDFGqgAoDsqYi6uNtpjmL/DPX/qmkbHAXUKxOtjTtxacfat2HgN97Gb7z" + + "+ZBNI5aaCSRoYwl+K9biWGID3EqsNmg0+2ELmFhE4mQZ78i7vNLTG7e5mj6v" + + "Qt+QuqN+daCbVqVTKxsFpODRRweobUTRxwEun6p0p3w3SUhR6p7ug1Jttgyu" + + "vfZug3PIk2j9fb26wAs2ZreVYut8hXpp/09ulCUudtlsYb/FD+H11v/JyopG" + + "2vYy0hL/gkMr41sGoVdyvzXeZUa7A1wYask+g7torad9sT8CPb3zXBd0kU2r" + + "lbSJIXQ8wTpheeUKe47YF9JVCF8WRc1dokD7fgfn6197pwyZpDEVrVyz1pUq" + + "jyum3ctONU4BSkAUVr9pTyeRFUeOE7SLuVu+c67PzNWXEc/HMVD4Hgs/idVc" + + "mrONk3xe385wFJK1iPe1kfRX5OXk9UWr2/yjgrahbkonWhJHnIlvs+b5rRKN" + + "qauwUZ+agMJV98Eyc2Lz0Lp/pNDRNjmGXeJLzAaAy46STov8sxwAgj3bQ7xu" + + "uEzdhJPDynAY5sWd3WnBY2ZhpawnToEKnD4u+eiH2MjUL2q/R2IPSmoyg9i2" + + "Ictgh4/ylrhm+lJDzcDrLDhC0m/t9EdhytH4erk/uCPcmAK/jpzFn6ltxcsx" + + "QjAbBgkqhkiG9w0BCRQxDh4MAGMAbABpAGUAbgB0MCMGCSqGSIb3DQEJFTEW" + + "BBS2wDxw7yH2OhKIgkDoQrTlavLvxQAAAAAAADCABgkqhkiG9w0BBwaggDCA" + + "AgEAMIAGCSqGSIb3DQEHATAoBgoqhkiG9w0BDAEGMBoEFORdyeTIG2oXDQBl" + + "I3aFNozDAkC2AgIEAKCABIIHICsc3D8rxLiDlegyXFfIejto66RW4u6b+d0C" + + "uAAz0G+dIvhQ9g3s++vUsX7x+icO/vjpgdo09aqtIg7T3suzfcHtU8CGSgtQ" + + "Tvml25LDC3IK3qI6cRqO+sCdvg18aS04IDKvDPYH4ca5btwPBIID6CStk/jY" + + "QFpnSI6VNz9IERi/nwuvuBYk+A0Z7+nQdhF+QkW1rzN+uz0dkNJt6ZbG5lEK" + + "GayV+FDTQcREMihYa716RN9sq3cm0jXXdttj998oS/QrpZDEcPqd4AM6EIL+" + + "PTA1tEQYxXa8msAPp+tLvXOtiD6v/4FO77EA7E5oR36a9en+M1QQasFU3VBf" + + "V9os92QlbtVUTkspJV9gXL6s4CGNptc7lUH+nIw65j9MOoyOU9w1qjPRlN/Z" + + "MTuhFooglE6TPd29Udwufqp+hHkW/7z5tBKkhGlZEClzD3IWhcF9NVraE/IV" + + "S5qVmx2Up7SeLZAXJ+AAznq5IXwE1dOUTkwYLcIrH1FuVA5rtOkB8Xt1LJq0" + + "ERkjJ5MfpxTxbKXp5PejzD98v54+s4INekcrI0jzz4pLsann7ex0r6CPsQsH" + + "+F3rBVaT3oHSKqoIm2Nw57oDjLLp5lP2qcCqps3y2dcVzu5NIzCSkVlxUaBK" + + "IT3xv0gvVJI7wnP0QM35MCywKkToJX5ajQKrDc4iCAAzmxaQzdBycxJPYByq" + + "VHvH7BJldJlMw5NHbTHlNoYKndMdAsHp7sUqERkDEGl80R86TlB4nJaDrfsx" + + "vL+KluiCY9AD7o+MEYZ9VYoNDUzVGH4pTr4wnv1UFoRWix5IZuDnnYkyijKD" + + "VtU5+mc0YtsPQIpKCBJOYt05bgpX5aPQ3s2lviYw3bvP0TrclYs/rx4wKVgW" + + "2GYLzPh0OVMBduCbzW1E58ieBsgRyQ7+2MTl9Nj+nznjCAfLSvrVEcwxVUQA" + + "ofcEbiECEJss2JNQq8erwgo8dP3atwQ1KeqMc8acICcOrI2rNxwVOLzPuCsl" + + "l8gwZOoxLZXuKMQbQu4as1HNS309dfWIWppvc3K4nDWg51HUCPbsIo3wm3rR" + + "igc/W3bf4Ppg0pLAS5c1s0Xau43u9GmIjGiDqYaasfcXnCKy2LNuUpbhoOC1" + + "o/wMC9gT45aJQ5vsVGe5XvfhLV7Y815EdI756s9PIEOnG8HbAtCAjOIVpQfP" + + "eF8+cnZyGGdsbmu7lYzg3whCpZ/L2RrTI86nEn5eePs4m2hDV0Oi9r6e2CIf" + + "nGUa0TB9jf1OMhOSBD+h4jx7b6uT+XLmG8qUxvkoItMDZLrJ0f8czO5MyOZa" + + "nEJoG42Fy2p7zD/qO72OUQISNmt8C1rQFsg9dBDib4DMu69vBsVrIV028sal" + + "+tq1UH3vFMbEYyVfPH3WDgxyHwUQK2qrz3WBdD/BMyuAV4DPI3SPTweROh8n" + + "yWJN1ppY9qybmTyHFCs6TRjPB9cVcdKSc0qYxgzblJiXXb3s9ANOb89aA3Ah" + + "anWnAhcEggLZN2yFCtrRuvJXvDQhj8qmye9UkjB2fEpWXV7H0natE3hSoB+C" + + "2krt3eBV0xJ1tLEco7T4zsbQQJRmeu/essOsfwpRfE5ZPoIeThf+UmWTsfsw" + + "r4fxeePMTy6iCnkF5/ro8k5WKnOsaV+HWy/ulwW2r/DMT3aDBWfHX5Hk8DpU" + + "+PlQhbyGTSTIJ/OFmbcWjMPt469o7+KrrF9IBrzJ42KzMw6xtKwtVb0232AM" + + "pIwnLzCHIiNO2qDBZAIDdF68+GU3RsEkHfR6d5myZVxnH4mhSCFFtHxgqTOz" + + "Ouo/uvgu72miZ0OFAy1zcMtfGMS3Md54MJkhSZq4ZgUo/EyJCeEDLGn8pMF1" + + "jX1WsUj96qMRyc+p2KnKs6ZL95BVa76SdIFz6ts6uoIem3drTXYJHNbw29OW" + + "Y0am+FmXTWFZFnin8Qu5Xct5l7FYIGA9VLOHL9Vtp+SXomcFEZpjMaxvtf4R" + + "xoAI2Bc9Ka+MNiz35O0JXhI9/t5uOdiN6ZOJlfpEWOK7ou5lDkZuDcrHvLvQ" + + "PocP2Yemd36xEgjFssR/tFITlhRBXHDeHwpvmXM4iiwD1wOGMqybXx/1g1m1" + + "0UBbKqDsgSLQC7c0TaRFJjj71T74PBMiapiQgijv9WINfmTgxNUukbK3Kqp/" + + "G3BmThoIDCB8WD1kxXBpaG62dSsih7yhPQJVEV3Y0tdkdChOk+Y3Wf8crV/Q" + + "P08pQH7H9yCi04S5fSJtIDtYARWhr1yl8EQMnu2X8J6r/DWcDmXUK4Bv1vqe" + + "tcnT5EAYFPeOMz21nonM3kJgUMNsxCQjKaEMEcUu8ZRnGUAFdG4lULPJn5NQ" + + "LTvWg8Y3GrHRLjpnd9k+8gWWzRIbBiwCwEbClMZffRd6kcA5ZoOhVngdyvvj" + + "BhkgadB5jC+ZRzExHxoEhzPJx3mxIVTqLuw7QxHz9OTcysvY/cGKCvmgzgk/" + + "TjTJsqcEAAAAAAAAAAAAAAAAAAAAAAAAMD0wITAJBgUrDgMCGgUABBQWfGA6" + + "lI+TXQiuXaa1V+LlHodhXAQUAwMIAAUvBYY+a7sXNlQeVEPAGkMCAgQAAAA="); +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/LoggingDatagramTransport.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/LoggingDatagramTransport.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/LoggingDatagramTransport.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/LoggingDatagramTransport.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,92 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; + +import org.bouncycastle.tls.DatagramTransport; +import org.bouncycastle.util.Strings; + +public class LoggingDatagramTransport + implements DatagramTransport +{ + + private static final String HEX_CHARS = "0123456789ABCDEF"; + + private final DatagramTransport transport; + private final PrintStream output; + private final long launchTimestamp; + + public LoggingDatagramTransport(DatagramTransport transport, PrintStream output) + { + this.transport = transport; + this.output = output; + this.launchTimestamp = System.currentTimeMillis(); + } + + public int getReceiveLimit() + throws IOException + { + return transport.getReceiveLimit(); + } + + public int getSendLimit() + throws IOException + { + return transport.getSendLimit(); + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + int length = transport.receive(buf, off, len, waitMillis); + if (length >= 0) + { + dumpDatagram("Received", buf, off, length); + } + return length; + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + dumpDatagram("Sending", buf, off, len); + transport.send(buf, off, len); + } + + public void close() + throws IOException + { + } + + private void dumpDatagram(String verb, byte[] buf, int off, int len) + throws IOException + { + long timestamp = System.currentTimeMillis() - launchTimestamp; + StringBuffer sb = new StringBuffer("(+" + timestamp + "ms) " + verb + " " + len + " byte datagram:"); + for (int pos = 0; pos < len; ++pos) + { + if (pos % 16 == 0) + { + sb.append(Strings.lineSeparator()); + sb.append(" "); + } + else if (pos % 16 == 8) + { + sb.append('-'); + } + else + { + sb.append(' '); + } + int val = buf[off + pos] & 0xFF; + sb.append(HEX_CHARS.charAt(val >> 4)); + sb.append(HEX_CHARS.charAt(val & 0xF)); + } + dump(sb.toString()); + } + + private synchronized void dump(String s) + { + output.println(s); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockDatagramAssociation.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockDatagramAssociation.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockDatagramAssociation.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockDatagramAssociation.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,110 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.util.Vector; + +import org.bouncycastle.tls.DatagramTransport; + +public class MockDatagramAssociation +{ + private int mtu; + private MockDatagramTransport client, server; + + public MockDatagramAssociation(int mtu) + { + this.mtu = mtu; + + Vector clientQueue = new Vector(); + Vector serverQueue = new Vector(); + + this.client = new MockDatagramTransport(clientQueue, serverQueue); + this.server = new MockDatagramTransport(serverQueue, clientQueue); + } + + public DatagramTransport getClient() + { + return client; + } + + public DatagramTransport getServer() + { + return server; + } + + private class MockDatagramTransport + implements DatagramTransport + { + private Vector receiveQueue, sendQueue; + + MockDatagramTransport(Vector receiveQueue, Vector sendQueue) + { + this.receiveQueue = receiveQueue; + this.sendQueue = sendQueue; + } + + public int getReceiveLimit() + throws IOException + { + return mtu; + } + + public int getSendLimit() + throws IOException + { + return mtu; + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + synchronized (receiveQueue) + { + if (receiveQueue.isEmpty()) + { + try + { + receiveQueue.wait(waitMillis); + } + catch (InterruptedException e) + { + // TODO Keep waiting until full wait expired? + } + if (receiveQueue.isEmpty()) + { + return -1; + } + } + DatagramPacket packet = (DatagramPacket)receiveQueue.remove(0); + int copyLength = Math.min(len, packet.getLength()); + System.arraycopy(packet.getData(), packet.getOffset(), buf, off, copyLength); + return copyLength; + } + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + if (len > mtu) + { + // TODO Simulate rejection? + } + + byte[] copy = new byte[len]; + System.arraycopy(buf, off, copy, 0, len); + DatagramPacket packet = new DatagramPacket(copy, len); + + synchronized (sendQueue) + { + sendQueue.addElement(packet); + sendQueue.notify(); + } + } + + public void close() + throws IOException + { + // TODO? + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSClient.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSClient.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSClient.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSClient.java 2016-10-04 18:54:30.000000000 +0000 @@ -0,0 +1,154 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.SecureRandom; +import java.util.Hashtable; + +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.CertificateRequest; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.DefaultTlsClient; +import org.bouncycastle.tls.MaxFragmentLength; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.TlsAuthentication; +import org.bouncycastle.tls.TlsCredentials; +import org.bouncycastle.tls.TlsExtensionsUtils; +import org.bouncycastle.tls.TlsSession; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + +public class MockDTLSClient + extends DefaultTlsClient +{ + protected TlsSession session; + + public MockDTLSClient(TlsSession session) + { + super(new BcTlsCrypto(new SecureRandom())); + + this.session = session; + } + + public TlsSession getSessionToResume() + { + return this.session; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("DTLS client raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println(message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("DTLS client received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + + public ProtocolVersion getClientVersion() + { + return ProtocolVersion.DTLSv12; + } + + public ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.DTLSv10; + } + + public Hashtable getClientExtensions() throws IOException + { + Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions()); + TlsExtensionsUtils.addEncryptThenMACExtension(clientExtensions); + TlsExtensionsUtils.addExtendedMasterSecretExtension(clientExtensions); + { + /* + * NOTE: If you are copying test code, do not blindly set these extensions in your own client. + */ + TlsExtensionsUtils.addMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9); + TlsExtensionsUtils.addPaddingExtension(clientExtensions, context.getCrypto().getSecureRandom().nextInt(16)); + TlsExtensionsUtils.addTruncatedHMacExtension(clientExtensions); + } + return clientExtensions; + } + + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + super.notifyServerVersion(serverVersion); + + System.out.println("Negotiated " + serverVersion); + } + + public TlsAuthentication getAuthentication() + throws IOException + { + return new TlsAuthentication() + { + public void notifyServerCertificate(org.bouncycastle.tls.Certificate serverCertificate) + throws IOException + { + TlsCertificate[] chain = serverCertificate.getCertificateList(); + System.out.println("DTLS client received server certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = Certificate.getInstance(chain[i].getEncoded()); + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + + public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) + throws IOException + { + short[] certificateTypes = certificateRequest.getCertificateTypes(); + if (certificateTypes == null || !Arrays.contains(certificateTypes, ClientCertificateType.rsa_sign)) + { + return null; + } + + return TlsTestUtils.loadSignerCredentials(context, certificateRequest.getSupportedSignatureAlgorithms(), + SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem"); + } + }; + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + TlsSession newSession = context.getResumableSession(); + if (newSession != null) + { + byte[] newSessionID = newSession.getSessionID(); + String hex = Hex.toHexString(newSessionID); + + if (this.session != null && Arrays.areEqual(this.session.getSessionID(), newSessionID)) + { + System.out.println("Resumed session: " + hex); + } + else + { + System.out.println("Established session: " + hex); + } + + this.session = newSession; + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSServer.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSServer.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSServer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSServer.java 2016-10-04 21:06:28.000000000 +0000 @@ -0,0 +1,105 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.SecureRandom; +import java.util.Vector; + +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.CertificateRequest; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.DefaultTlsServer; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.TlsCredentialedDecryptor; +import org.bouncycastle.tls.TlsCredentialedSigner; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; + +public class MockDTLSServer + extends DefaultTlsServer +{ + MockDTLSServer() + { + super(new BcTlsCrypto(new SecureRandom())); + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("DTLS server raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println(message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("DTLS server received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + + public CertificateRequest getCertificateRequest() throws IOException + { + short[] certificateTypes = new short[]{ ClientCertificateType.rsa_sign, + ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign }; + + Vector serverSigAlgs = null; + if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(serverVersion)) + { + serverSigAlgs = TlsUtils.getDefaultSupportedSignatureAlgorithms(); + } + + Vector certificateAuthorities = new Vector(); + certificateAuthorities.addElement(TlsTestUtils.loadBcCertificateResource("x509-ca.pem").getSubject()); + + return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities); + } + + public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCertificate) + throws IOException + { + TlsCertificate[] chain = clientCertificate.getCertificateList(); + System.out.println("DTLS server received client certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = Certificate.getInstance(chain[i].getEncoded()); + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + entry.getSubject() + + ")"); + } + } + + protected ProtocolVersion getMaximumVersion() + { + return ProtocolVersion.DTLSv12; + } + + protected ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.DTLSv10; + } + + protected TlsCredentialedDecryptor getRSAEncryptionCredentials() + throws IOException + { + return TlsTestUtils.loadEncryptionCredentials(context, new String[]{"x509-server.pem", "x509-ca.pem"}, + "x509-server-key.pem"); + } + + protected TlsCredentialedSigner getRSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, supportedSignatureAlgorithms, SignatureAlgorithm.rsa, + "x509-server.pem", "x509-server-key.pem"); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsClient.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsClient.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsClient.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsClient.java 2016-10-04 18:54:30.000000000 +0000 @@ -0,0 +1,129 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.SecureRandom; +import java.util.Hashtable; + +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.BasicTlsPSKIdentity; +import org.bouncycastle.tls.PSKTlsClient; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.ServerOnlyTlsAuthentication; +import org.bouncycastle.tls.TlsAuthentication; +import org.bouncycastle.tls.TlsExtensionsUtils; +import org.bouncycastle.tls.TlsPSKIdentity; +import org.bouncycastle.tls.TlsSession; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + +class MockPSKTlsClient + extends PSKTlsClient +{ + TlsSession session; + + MockPSKTlsClient(TlsSession session) + { + this(session, new BasicTlsPSKIdentity("client", new byte[16])); + } + + MockPSKTlsClient(TlsSession session, TlsPSKIdentity pskIdentity) + { + super(new BcTlsCrypto(new SecureRandom()), pskIdentity); + + this.session = session; + } + + public TlsSession getSessionToResume() + { + return this.session; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-PSK client raised alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-PSK client received alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + TlsSession newSession = context.getResumableSession(); + if (newSession != null) + { + byte[] newSessionID = newSession.getSessionID(); + String hex = Hex.toHexString(newSessionID); + + if (this.session != null && Arrays.areEqual(this.session.getSessionID(), newSessionID)) + { + System.out.println("Resumed session: " + hex); + } + else + { + System.out.println("Established session: " + hex); + } + + this.session = newSession; + } + } + + public ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.TLSv12; + } + + public Hashtable getClientExtensions() throws IOException + { + Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions()); + TlsExtensionsUtils.addEncryptThenMACExtension(clientExtensions); + return clientExtensions; + } + + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + super.notifyServerVersion(serverVersion); + + System.out.println("TLS-PSK client negotiated " + serverVersion); + } + + public TlsAuthentication getAuthentication() throws IOException + { + return new ServerOnlyTlsAuthentication() + { + public void notifyServerCertificate(org.bouncycastle.tls.Certificate serverCertificate) + throws IOException + { + TlsCertificate[] chain = serverCertificate.getCertificateList(); + System.out.println("TLS-PSK client received server certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = Certificate.getInstance(chain[i].getEncoded()); + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + }; + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsServer.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsServer.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsServer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsServer.java 2016-10-08 22:56:31.000000000 +0000 @@ -0,0 +1,99 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.SecureRandom; + +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.PSKTlsServer; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.TlsCredentialedDecryptor; +import org.bouncycastle.tls.TlsPSKIdentityManager; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.util.Strings; + +class MockPSKTlsServer + extends PSKTlsServer +{ + MockPSKTlsServer() + { + super(new BcTlsCrypto(new SecureRandom()), new MyIdentityManager()); + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-PSK server raised alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-PSK server received alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + byte[] pskIdentity = context.getSecurityParameters().getPSKIdentity(); + if (pskIdentity != null) + { + String name = Strings.fromUTF8ByteArray(pskIdentity); + System.out.println("TLS-PSK server completed handshake for PSK identity: " + name); + } + } + + protected ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.TLSv12; + } + + public ProtocolVersion getServerVersion() throws IOException + { + ProtocolVersion serverVersion = super.getServerVersion(); + + System.out.println("TLS-PSK server negotiated " + serverVersion); + + return serverVersion; + } + + protected TlsCredentialedDecryptor getRSAEncryptionCredentials() throws IOException + { + return TlsTestUtils.loadEncryptionCredentials(context, new String[]{ "x509-server.pem", "x509-ca.pem" }, + "x509-server-key.pem"); + } + + static class MyIdentityManager + implements TlsPSKIdentityManager + { + public byte[] getHint() + { + return Strings.toUTF8ByteArray("hint"); + } + + public byte[] getPSK(byte[] identity) + { + if (identity != null) + { + String name = Strings.fromUTF8ByteArray(identity); + if (name.equals("client")) + { + return new byte[16]; + } + } + return null; + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsClient.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsClient.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsClient.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsClient.java 2016-10-04 18:54:30.000000000 +0000 @@ -0,0 +1,122 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.SecureRandom; +import java.util.Hashtable; + +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SRPTlsClient; +import org.bouncycastle.tls.ServerOnlyTlsAuthentication; +import org.bouncycastle.tls.TlsAuthentication; +import org.bouncycastle.tls.TlsExtensionsUtils; +import org.bouncycastle.tls.TlsSession; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + +class MockSRPTlsClient + extends SRPTlsClient +{ + TlsSession session; + + MockSRPTlsClient(TlsSession session, byte[] identity, byte[] password) + { + super(new BcTlsCrypto(new SecureRandom()), identity, password); + + this.session = session; + } + + public TlsSession getSessionToResume() + { + return this.session; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-SRP client raised alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-SRP client received alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + TlsSession newSession = context.getResumableSession(); + if (newSession != null) + { + byte[] newSessionID = newSession.getSessionID(); + String hex = Hex.toHexString(newSessionID); + + if (this.session != null && Arrays.areEqual(this.session.getSessionID(), newSessionID)) + { + System.out.println("Resumed session: " + hex); + } + else + { + System.out.println("Established session: " + hex); + } + + this.session = newSession; + } + } + + public ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.TLSv12; + } + + public Hashtable getClientExtensions() throws IOException + { + Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions()); + TlsExtensionsUtils.addEncryptThenMACExtension(clientExtensions); + return clientExtensions; + } + + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + super.notifyServerVersion(serverVersion); + + System.out.println("TLS-SRP client negotiated " + serverVersion); + } + + public TlsAuthentication getAuthentication() throws IOException + { + return new ServerOnlyTlsAuthentication() + { + public void notifyServerCertificate(org.bouncycastle.tls.Certificate serverCertificate) + throws IOException + { + TlsCertificate[] chain = serverCertificate.getCertificateList(); + System.out.println("TLS-SRP client received server certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = Certificate.getInstance(chain[i].getEncoded()); + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + }; + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsServer.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsServer.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsServer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsServer.java 2016-10-08 22:56:31.000000000 +0000 @@ -0,0 +1,131 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.crypto.agreement.srp.SRP6VerifierGenerator; +import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SRPTlsServer; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.SimulatedTlsSRPIdentityManager; +import org.bouncycastle.tls.TlsCredentialedSigner; +import org.bouncycastle.tls.TlsSRPIdentityManager; +import org.bouncycastle.tls.TlsSRPLoginParameters; +import org.bouncycastle.tls.crypto.SRP6Group; +import org.bouncycastle.tls.crypto.SRP6StandardGroups; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsSRPConfig; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +class MockSRPTlsServer + extends SRPTlsServer +{ + static final SRP6Group TEST_GROUP = SRP6StandardGroups.rfc5054_1024; + static final byte[] TEST_IDENTITY = Strings.toUTF8ByteArray("client"); + static final byte[] TEST_PASSWORD = Strings.toUTF8ByteArray("password"); + static final byte[] TEST_SALT = Strings.toUTF8ByteArray("salt"); + static final byte[] TEST_SEED_KEY = Strings.toUTF8ByteArray("seed_key"); + + MockSRPTlsServer() + throws IOException + { + super(new BcTlsCrypto(new SecureRandom()), new MyIdentityManager(new BcTlsCrypto(new SecureRandom()))); + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-SRP server raised alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-SRP server received alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + byte[] srpIdentity = context.getSecurityParameters().getSRPIdentity(); + if (srpIdentity != null) + { + String name = Strings.fromUTF8ByteArray(srpIdentity); + System.out.println("TLS-SRP server completed handshake for SRP identity: " + name); + } + } + + protected ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.TLSv12; + } + + public ProtocolVersion getServerVersion() throws IOException + { + ProtocolVersion serverVersion = super.getServerVersion(); + + System.out.println("TLS-SRP server negotiated " + serverVersion); + + return serverVersion; + } + + protected TlsCredentialedSigner getDSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, supportedSignatureAlgorithms, SignatureAlgorithm.dsa, + "x509-server-dsa.pem", "x509-server-key-dsa.pem"); + } + + protected TlsCredentialedSigner getRSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, supportedSignatureAlgorithms, SignatureAlgorithm.rsa, + "x509-server.pem", "x509-server-key.pem"); + } + + static class MyIdentityManager + implements TlsSRPIdentityManager + { + protected SimulatedTlsSRPIdentityManager unknownIdentityManager; + + MyIdentityManager(TlsCrypto crypto) + throws IOException + { + unknownIdentityManager = SimulatedTlsSRPIdentityManager.getRFC5054Default(crypto, TEST_GROUP, TEST_SEED_KEY); + } + + public TlsSRPLoginParameters getLoginParameters(byte[] identity) + { + if (Arrays.areEqual(TEST_IDENTITY, identity)) + { + SRP6VerifierGenerator verifierGenerator = new SRP6VerifierGenerator(); + verifierGenerator.init(TEST_GROUP.getN(), TEST_GROUP.getG(), new SHA1Digest()); + + BigInteger verifier = verifierGenerator.generateVerifier(TEST_SALT, identity, TEST_PASSWORD); + + TlsSRPConfig srpConfig = new TlsSRPConfig(); + srpConfig.setExplicitNG(new BigInteger[]{ TEST_GROUP.getN(), TEST_GROUP.getG() }); + + return new TlsSRPLoginParameters(srpConfig, verifier, TEST_SALT); + } + + return unknownIdentityManager.getLoginParameters(identity); + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockTlsClient.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockTlsClient.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockTlsClient.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockTlsClient.java 2016-12-02 22:04:06.000000000 +0000 @@ -0,0 +1,153 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.SecureRandom; +import java.util.Hashtable; + +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.CertificateRequest; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.DefaultTlsClient; +import org.bouncycastle.tls.MaxFragmentLength; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.TlsAuthentication; +import org.bouncycastle.tls.TlsCredentials; +import org.bouncycastle.tls.TlsExtensionsUtils; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsSession; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + +class MockTlsClient + extends DefaultTlsClient +{ + TlsSession session; + + MockTlsClient(TlsSession session) + { + super(new BcTlsCrypto(new SecureRandom())); + + this.session = session; + } + + public TlsSession getSessionToResume() + { + return this.session; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS client raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS client received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + + public Hashtable getClientExtensions() throws IOException + { + Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions()); + TlsExtensionsUtils.addEncryptThenMACExtension(clientExtensions); + TlsExtensionsUtils.addExtendedMasterSecretExtension(clientExtensions); + { + /* + * NOTE: If you are copying test code, do not blindly set these extensions in your own client. + */ + TlsExtensionsUtils.addMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9); + TlsExtensionsUtils.addPaddingExtension(clientExtensions, context.getCrypto().getSecureRandom().nextInt(16)); + TlsExtensionsUtils.addTruncatedHMacExtension(clientExtensions); + } + return clientExtensions; + } + + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + super.notifyServerVersion(serverVersion); + + System.out.println("TLS client negotiated " + serverVersion); + } + + public TlsAuthentication getAuthentication() + throws IOException + { + return new TlsAuthentication() + { + public void notifyServerCertificate(org.bouncycastle.tls.Certificate serverCertificate) + throws IOException + { + TlsCertificate[] chain = serverCertificate.getCertificateList(); + + System.out.println("TLS client received server certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = Certificate.getInstance(chain[i].getEncoded()); + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + + boolean isEmpty = serverCertificate == null || serverCertificate.isEmpty(); + if (isEmpty || !TlsTestUtils.isCertificateOneOf(context.getCrypto(), chain[0], + new String[]{ "x509-server.pem", "x509-server-dsa.pem", "x509-server-ecdsa.pem"})) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + } + + public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) + throws IOException + { + short[] certificateTypes = certificateRequest.getCertificateTypes(); + if (certificateTypes == null || !Arrays.contains(certificateTypes, ClientCertificateType.rsa_sign)) + { + return null; + } + + return TlsTestUtils.loadSignerCredentials(context, certificateRequest.getSupportedSignatureAlgorithms(), + SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem"); + } + }; + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + TlsSession newSession = context.getResumableSession(); + if (newSession != null) + { + byte[] newSessionID = newSession.getSessionID(); + String hex = Hex.toHexString(newSessionID); + + if (this.session != null && Arrays.areEqual(this.session.getSessionID(), newSessionID)) + { + System.out.println("Resumed session: " + hex); + } + else + { + System.out.println("Established session: " + hex); + } + + this.session = newSession; + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockTlsServer.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockTlsServer.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/MockTlsServer.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/MockTlsServer.java 2016-12-02 22:04:06.000000000 +0000 @@ -0,0 +1,113 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.SecureRandom; +import java.util.Vector; + +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.CertificateRequest; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.DefaultTlsServer; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.TlsCredentialedDecryptor; +import org.bouncycastle.tls.TlsCredentialedSigner; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; + +class MockTlsServer + extends DefaultTlsServer +{ + MockTlsServer() + { + super(new BcTlsCrypto(new SecureRandom())); + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS server raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS server received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + + public ProtocolVersion getServerVersion() throws IOException + { + ProtocolVersion serverVersion = super.getServerVersion(); + + System.out.println("TLS server negotiated " + serverVersion); + + return serverVersion; + } + + public CertificateRequest getCertificateRequest() throws IOException + { + short[] certificateTypes = new short[]{ ClientCertificateType.rsa_sign, + ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign }; + + Vector serverSigAlgs = null; + if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(serverVersion)) + { + serverSigAlgs = TlsUtils.getDefaultSupportedSignatureAlgorithms(); + } + + Vector certificateAuthorities = new Vector(); + certificateAuthorities.addElement(TlsTestUtils.loadBcCertificateResource("x509-ca.pem").getSubject()); + + return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities); + } + + public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCertificate) + throws IOException + { + TlsCertificate[] chain = clientCertificate.getCertificateList(); + + System.out.println("TLS server received client certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = Certificate.getInstance(chain[i].getEncoded()); + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + + boolean isEmpty = (clientCertificate == null || clientCertificate.isEmpty()); + if (!isEmpty && !TlsTestUtils.isCertificateOneOf(context.getCrypto(), chain[0], + new String[]{ "x509-client.pem", "x509-client-dsa.pem", "x509-client-ecdsa.pem"})) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + } + + protected TlsCredentialedDecryptor getRSAEncryptionCredentials() + throws IOException + { + return TlsTestUtils.loadEncryptionCredentials(context, new String[]{"x509-server.pem", "x509-ca.pem"}, + "x509-server-key.pem"); + } + + protected TlsCredentialedSigner getRSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, supportedSignatureAlgorithms, SignatureAlgorithm.rsa, + "x509-server.pem", "x509-server-key.pem"); + } +} \ No newline at end of file diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/NetworkInputStream.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/NetworkInputStream.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/NetworkInputStream.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/NetworkInputStream.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,60 @@ +package org.bouncycastle.tls.test; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Tracks and enforces close() calls, without closing the underlying InputStream + */ +class NetworkInputStream extends FilterInputStream +{ + boolean closed = false; + + public NetworkInputStream(InputStream input) + { + super(input); + } + + synchronized boolean isClosed() + { + return closed; + } + + public int available() throws IOException + { + checkNotClosed(); + return in.available(); + } + + public synchronized void close() throws IOException + { + closed = true; + } + + public int read() throws IOException + { + checkNotClosed(); + return in.read(); + } + + public int read(byte[] b) throws IOException + { + checkNotClosed(); + return in.read(b); + } + + public int read(byte[] b, int off, int len) throws IOException + { + checkNotClosed(); + return in.read(b, off, len); + } + + protected synchronized void checkNotClosed() throws IOException + { + if (closed) + { + throw new IOException("NetworkInputStream closed"); + } + } +} \ No newline at end of file diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/NetworkOutputStream.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/NetworkOutputStream.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/NetworkOutputStream.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/NetworkOutputStream.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,54 @@ +package org.bouncycastle.tls.test; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * Tracks and enforces close() calls, without closing the underlying OutputStream + */ +class NetworkOutputStream extends FilterOutputStream +{ + boolean closed = false; + + public NetworkOutputStream(OutputStream output) + { + super(output); + } + + synchronized boolean isClosed() + { + return closed; + } + + public synchronized void close() throws IOException + { + closed = true; + } + + public void write(int b) throws IOException + { + checkNotClosed(); + out.write(b); + } + + public void write(byte[] b) throws IOException + { + checkNotClosed(); + out.write(b); + } + + public void write(byte[] b, int off, int len) throws IOException + { + checkNotClosed(); + out.write(b, off, len); + } + + protected synchronized void checkNotClosed() throws IOException + { + if (closed) + { + throw new IOException("NetworkOutputStream closed"); + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/PSKTlsClientTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/PSKTlsClientTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/PSKTlsClientTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/PSKTlsClientTest.java 2016-10-25 06:04:03.000000000 +0000 @@ -0,0 +1,79 @@ +package org.bouncycastle.tls.test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; + +import org.bouncycastle.tls.BasicTlsPSKIdentity; +import org.bouncycastle.tls.TlsClient; +import org.bouncycastle.tls.TlsClientProtocol; + +/** + * A simple test designed to conduct a TLS handshake with an external TLS server. + *

      + * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external TLS server. + *

      + * In both cases, extra options are required to enable PSK ciphersuites and configure identities/keys. + *

      + */ +public class PSKTlsClientTest +{ + public static void main(String[] args) throws Exception + { + InetAddress address = InetAddress.getLocalHost(); + int port = 5556; + + long time1 = System.currentTimeMillis(); + + /* + * Note: This is the default PSK identity for 'openssl s_server' testing, the server must be + * started with "-psk 6161616161" to make the keys match, and possibly the "-psk_hint" + * option should be present. + */ + String psk_identity = "Client_identity"; + byte[] psk = new byte[]{ 0x61, 0x61, 0x61, 0x61, 0x61 }; + + BasicTlsPSKIdentity pskIdentity = new BasicTlsPSKIdentity(psk_identity, psk); + + MockPSKTlsClient client = new MockPSKTlsClient(null, pskIdentity); + TlsClientProtocol protocol = openTlsConnection(address, port, client); + protocol.close(); + + long time2 = System.currentTimeMillis(); + System.out.println("Elapsed 1: " + (time2 - time1) + "ms"); + + client = new MockPSKTlsClient(client.getSessionToResume(), pskIdentity); + protocol = openTlsConnection(address, port, client); + + long time3 = System.currentTimeMillis(); + System.out.println("Elapsed 2: " + (time3 - time2) + "ms"); + + OutputStream output = protocol.getOutputStream(); + output.write("GET / HTTP/1.1\r\n\r\n".getBytes("UTF-8")); + output.flush(); + + InputStream input = protocol.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(input)); + + String line; + while ((line = reader.readLine()) != null) + { + System.out.println(">>> " + line); + } + + protocol.close(); + } + + static TlsClientProtocol openTlsConnection(InetAddress address, int port, TlsClient client) throws IOException + { + Socket s = new Socket(address, port); + TlsClientProtocol protocol = new TlsClientProtocol(s.getInputStream(), s.getOutputStream()); + protocol.connect(client); + return protocol; + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsClientTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsClientTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsClientTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsClientTest.java 2016-10-25 06:04:03.000000000 +0000 @@ -0,0 +1,67 @@ +package org.bouncycastle.tls.test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; + +import org.bouncycastle.tls.TlsClient; +import org.bouncycastle.tls.TlsClientProtocol; + +/** + * A simple test designed to conduct a TLS handshake with an external TLS server. + *

      + * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external TLS server. + *

      + */ +public class TlsClientTest +{ + public static void main(String[] args) + throws Exception + { + InetAddress address = InetAddress.getLocalHost(); + int port = 5556; + + long time1 = System.currentTimeMillis(); + + MockTlsClient client = new MockTlsClient(null); + TlsClientProtocol protocol = openTlsConnection(address, port, client); + protocol.close(); + + long time2 = System.currentTimeMillis(); + System.out.println("Elapsed 1: " + (time2 - time1) + "ms"); + + client = new MockTlsClient(client.getSessionToResume()); + protocol = openTlsConnection(address, port, client); + + long time3 = System.currentTimeMillis(); + System.out.println("Elapsed 2: " + (time3 - time2) + "ms"); + + OutputStream output = protocol.getOutputStream(); + output.write("GET / HTTP/1.1\r\n\r\n".getBytes("UTF-8")); + output.flush(); + + InputStream input = protocol.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(input)); + + String line; + while ((line = reader.readLine()) != null) + { + System.out.println(">>> " + line); + } + + protocol.close(); + } + + static TlsClientProtocol openTlsConnection(InetAddress address, int port, TlsClient client) throws IOException + { + Socket s = new Socket(address, port); + TlsClientProtocol protocol = new TlsClientProtocol(s.getInputStream(), s.getOutputStream()); + protocol.connect(client); + return protocol; + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolNonBlockingTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolNonBlockingTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolNonBlockingTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolNonBlockingTest.java 2016-11-28 10:06:34.000000000 +0000 @@ -0,0 +1,125 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.security.SecureRandom; + +import junit.framework.TestCase; +import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsProtocol; +import org.bouncycastle.tls.TlsServerProtocol; +import org.bouncycastle.util.Arrays; + +public class TlsProtocolNonBlockingTest + extends TestCase +{ + public void testClientServerFragmented() throws IOException + { + // tests if it's really non-blocking when partial records arrive + testClientServer(true); + } + + public void testClientServerNonFragmented() throws IOException + { + testClientServer(false); + } + + private static void testClientServer(boolean fragment) throws IOException + { + SecureRandom secureRandom = new SecureRandom(); + + TlsClientProtocol clientProtocol = new TlsClientProtocol(); + TlsServerProtocol serverProtocol = new TlsServerProtocol(); + + clientProtocol.connect(new MockTlsClient(null)); + serverProtocol.accept(new MockTlsServer()); + + // pump handshake + boolean hadDataFromServer = true; + boolean hadDataFromClient = true; + while (hadDataFromServer || hadDataFromClient) + { + hadDataFromServer = pumpData(serverProtocol, clientProtocol, fragment); + hadDataFromClient = pumpData(clientProtocol, serverProtocol, fragment); + } + + // send data in both directions + byte[] data = new byte[1024]; + secureRandom.nextBytes(data); + writeAndRead(clientProtocol, serverProtocol, data, fragment); + writeAndRead(serverProtocol, clientProtocol, data, fragment); + + // close the connection + clientProtocol.close(); + pumpData(clientProtocol, serverProtocol, fragment); + checkClosed(serverProtocol); + checkClosed(clientProtocol); + } + + private static void writeAndRead(TlsProtocol writer, TlsProtocol reader, byte[] data, boolean fragment) + throws IOException + { + int dataSize = data.length; + writer.writeApplicationData(data, 0, dataSize); + pumpData(writer, reader, fragment); + + assertEquals(dataSize, reader.getAvailableInputBytes()); + byte[] readData = new byte[dataSize]; + reader.readInput(readData, 0, dataSize); + assertArrayEquals(data, readData); + } + + private static boolean pumpData(TlsProtocol from, TlsProtocol to, boolean fragment) throws IOException + { + int byteCount = from.getAvailableOutputBytes(); + if (byteCount == 0) + { + return false; + } + + if (fragment) + { + while (from.getAvailableOutputBytes() > 0) + { + byte[] buffer = new byte[1]; + from.readOutput(buffer, 0, 1); + to.offerInput(buffer); + } + } + else + { + byte[] buffer = new byte[byteCount]; + from.readOutput(buffer, 0, buffer.length); + to.offerInput(buffer); + } + + return true; + } + + private static void checkClosed(TlsProtocol protocol) + { + assertTrue(protocol.isClosed()); + + try + { + protocol.offerInput(new byte[10]); + fail("Input was accepted after close"); + } + catch (IOException e) + { + } + + try + { + protocol.writeApplicationData(new byte[10], 0, 10); + fail("Output was accepted after close"); + } + catch (IOException e) + { + } + } + + private static void assertArrayEquals(byte[] a, byte[] b) + { + assertTrue(Arrays.areEqual(a, b)); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolTest.java 2016-10-25 06:04:03.000000000 +0000 @@ -0,0 +1,81 @@ +package org.bouncycastle.tls.test; + +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.security.SecureRandom; + +import junit.framework.TestCase; +import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsServerProtocol; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.io.Streams; + +public class TlsProtocolTest + extends TestCase +{ + public void testClientServer() + throws Exception + { + SecureRandom secureRandom = new SecureRandom(); + + PipedInputStream clientRead = new PipedInputStream(); + PipedInputStream serverRead = new PipedInputStream(); + PipedOutputStream clientWrite = new PipedOutputStream(serverRead); + PipedOutputStream serverWrite = new PipedOutputStream(clientRead); + + TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); + TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); + + ServerThread serverThread = new ServerThread(serverProtocol); + serverThread.start(); + + MockTlsClient client = new MockTlsClient(null); + clientProtocol.connect(client); + + // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity + int length = 1000; + + byte[] data = new byte[length]; + secureRandom.nextBytes(data); + + OutputStream output = clientProtocol.getOutputStream(); + output.write(data); + + byte[] echo = new byte[data.length]; + int count = Streams.readFully(clientProtocol.getInputStream(), echo); + + assertEquals(count, data.length); + assertTrue(Arrays.areEqual(data, echo)); + + output.close(); + + serverThread.join(); + } + + static class ServerThread + extends Thread + { + private final TlsServerProtocol serverProtocol; + + ServerThread(TlsServerProtocol serverProtocol) + { + this.serverProtocol = serverProtocol; + } + + public void run() + { + try + { + MockTlsServer server = new MockTlsServer(); + serverProtocol.accept(server); + Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream()); + serverProtocol.close(); + } + catch (Exception e) + { +// throw new RuntimeException(e); + } + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsPSKProtocolTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsPSKProtocolTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsPSKProtocolTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsPSKProtocolTest.java 2016-10-25 06:04:03.000000000 +0000 @@ -0,0 +1,80 @@ +package org.bouncycastle.tls.test; + +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.security.SecureRandom; + +import junit.framework.TestCase; +import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsServerProtocol; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.io.Streams; + +public class TlsPSKProtocolTest + extends TestCase +{ + public void testClientServer() throws Exception + { + SecureRandom secureRandom = new SecureRandom(); + + PipedInputStream clientRead = new PipedInputStream(); + PipedInputStream serverRead = new PipedInputStream(); + PipedOutputStream clientWrite = new PipedOutputStream(serverRead); + PipedOutputStream serverWrite = new PipedOutputStream(clientRead); + + TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); + TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); + + ServerThread serverThread = new ServerThread(serverProtocol); + serverThread.start(); + + MockPSKTlsClient client = new MockPSKTlsClient(null); + clientProtocol.connect(client); + + // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity + int length = 1000; + + byte[] data = new byte[length]; + secureRandom.nextBytes(data); + + OutputStream output = clientProtocol.getOutputStream(); + output.write(data); + + byte[] echo = new byte[data.length]; + int count = Streams.readFully(clientProtocol.getInputStream(), echo); + + assertEquals(count, data.length); + assertTrue(Arrays.areEqual(data, echo)); + + output.close(); + + serverThread.join(); + } + + static class ServerThread + extends Thread + { + private final TlsServerProtocol serverProtocol; + + ServerThread(TlsServerProtocol serverProtocol) + { + this.serverProtocol = serverProtocol; + } + + public void run() + { + try + { + MockPSKTlsServer server = new MockPSKTlsServer(); + serverProtocol.accept(server); + Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream()); + serverProtocol.close(); + } + catch (Exception e) + { + // throw new RuntimeException(e); + } + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsServerTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsServerTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsServerTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsServerTest.java 2016-09-26 00:53:43.000000000 +0000 @@ -0,0 +1,79 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; + +import org.bouncycastle.tls.TlsServerProtocol; +import org.bouncycastle.util.io.Streams; +import org.bouncycastle.util.io.TeeOutputStream; + +/** + * A simple test designed to conduct a TLS handshake with an external TLS client. + *

      + * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external TLS client. + *

      + */ +public class TlsServerTest +{ + public static void main(String[] args) + throws Exception + { + InetAddress address = InetAddress.getLocalHost(); + int port = 5556; + + ServerSocket ss = new ServerSocket(port, 16, address); + while (true) + { + Socket s = ss.accept(); + System.out.println("--------------------------------------------------------------------------------"); + System.out.println("Accepted " + s); + ServerThread t = new ServerThread(s); + t.start(); + } + } + + static class ServerThread + extends Thread + { + private final Socket s; + + ServerThread(Socket s) + { + this.s = s; + } + + public void run() + { + try + { + MockTlsServer server = new MockTlsServer(); + TlsServerProtocol serverProtocol = new TlsServerProtocol(s.getInputStream(), s.getOutputStream()); + serverProtocol.accept(server); + OutputStream log = new TeeOutputStream(serverProtocol.getOutputStream(), System.out); + Streams.pipeAll(serverProtocol.getInputStream(), log); + serverProtocol.close(); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + finally + { + try + { + s.close(); + } + catch (IOException e) + { + } + finally + { + } + } + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsSRPProtocolTest.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsSRPProtocolTest.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsSRPProtocolTest.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsSRPProtocolTest.java 2016-10-25 06:04:03.000000000 +0000 @@ -0,0 +1,80 @@ +package org.bouncycastle.tls.test; + +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.security.SecureRandom; + +import junit.framework.TestCase; +import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsServerProtocol; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.io.Streams; + +public class TlsSRPProtocolTest + extends TestCase +{ + public void testClientServer() throws Exception + { + SecureRandom secureRandom = new SecureRandom(); + + PipedInputStream clientRead = new PipedInputStream(); + PipedInputStream serverRead = new PipedInputStream(); + PipedOutputStream clientWrite = new PipedOutputStream(serverRead); + PipedOutputStream serverWrite = new PipedOutputStream(clientRead); + + TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); + TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); + + ServerThread serverThread = new ServerThread(serverProtocol); + serverThread.start(); + + MockSRPTlsClient client = new MockSRPTlsClient(null, MockSRPTlsServer.TEST_IDENTITY, MockSRPTlsServer.TEST_PASSWORD); + clientProtocol.connect(client); + + // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity + int length = 1000; + + byte[] data = new byte[length]; + secureRandom.nextBytes(data); + + OutputStream output = clientProtocol.getOutputStream(); + output.write(data); + + byte[] echo = new byte[data.length]; + int count = Streams.readFully(clientProtocol.getInputStream(), echo); + + assertEquals(count, data.length); + assertTrue(Arrays.areEqual(data, echo)); + + output.close(); + + serverThread.join(); + } + + static class ServerThread + extends Thread + { + private final TlsServerProtocol serverProtocol; + + ServerThread(TlsServerProtocol serverProtocol) + { + this.serverProtocol = serverProtocol; + } + + public void run() + { + try + { + MockSRPTlsServer server = new MockSRPTlsServer(); + serverProtocol.accept(server); + Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream()); + serverProtocol.close(); + } + catch (Exception e) + { + //throw new RuntimeException(e); + } + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestCase.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestCase.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestCase.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestCase.java 2016-10-25 06:04:03.000000000 +0000 @@ -0,0 +1,186 @@ +package org.bouncycastle.tls.test; + +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.security.SecureRandom; + +import junit.framework.TestCase; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.io.Streams; + +public class TlsTestCase extends TestCase +{ + private static void checkTLSVersion(ProtocolVersion version) + { + if (version != null && !version.isTLS()) + { + throw new IllegalStateException("Non-TLS version"); + } + } + + protected final TlsTestConfig config; + + public TlsTestCase(String name) + { + super(name); + + this.config = null; + } + + public TlsTestCase(TlsTestConfig config, String name) + { + super(name); + + checkTLSVersion(config.clientMinimumVersion); + checkTLSVersion(config.clientOfferVersion); + checkTLSVersion(config.serverMaximumVersion); + checkTLSVersion(config.serverMinimumVersion); + + this.config = config; + } + + public void testDummy() + { + // Avoid "No tests found" warning from junit + } + + protected void runTest() throws Throwable + { + // Disable the test if it is not being run via TlsTestSuite + if (config == null) + { + return; + } + + SecureRandom secureRandom = new SecureRandom(); + + PipedInputStream clientRead = new PipedInputStream(); + PipedInputStream serverRead = new PipedInputStream(); + PipedOutputStream clientWrite = new PipedOutputStream(serverRead); + PipedOutputStream serverWrite = new PipedOutputStream(clientRead); + + NetworkInputStream clientNetIn = new NetworkInputStream(clientRead); + NetworkInputStream serverNetIn = new NetworkInputStream(serverRead); + NetworkOutputStream clientNetOut = new NetworkOutputStream(clientWrite); + NetworkOutputStream serverNetOut = new NetworkOutputStream(serverWrite); + + TlsTestClientProtocol clientProtocol = new TlsTestClientProtocol(clientNetIn, clientNetOut, config); + TlsTestServerProtocol serverProtocol = new TlsTestServerProtocol(serverNetIn, serverNetOut, config); + + TlsTestClientImpl clientImpl = new TlsTestClientImpl(config); + TlsTestServerImpl serverImpl = new TlsTestServerImpl(config); + + ServerThread serverThread = new ServerThread(serverProtocol, serverImpl); + serverThread.start(); + + Exception caught = null; + try + { + clientProtocol.connect(clientImpl); + + // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity + int length = 1000; + + byte[] data = new byte[length]; + secureRandom.nextBytes(data); + + OutputStream output = clientProtocol.getOutputStream(); + output.write(data); + + byte[] echo = new byte[data.length]; + int count = Streams.readFully(clientProtocol.getInputStream(), echo); + + assertEquals(count, data.length); + assertTrue(Arrays.areEqual(data, echo)); + + output.close(); + } + catch (Exception e) + { + caught = e; + logException(caught); + } + + serverThread.allowExit(); + serverThread.join(); + + assertTrue("Client InputStream not closed", clientNetIn.isClosed()); + assertTrue("Client OutputStream not closed", clientNetOut.isClosed()); + assertTrue("Server InputStream not closed", serverNetIn.isClosed()); + assertTrue("Server OutputStream not closed", serverNetOut.isClosed()); + + assertEquals("Client fatal alert connection end", config.expectFatalAlertConnectionEnd, clientImpl.firstFatalAlertConnectionEnd); + assertEquals("Server fatal alert connection end", config.expectFatalAlertConnectionEnd, serverImpl.firstFatalAlertConnectionEnd); + + assertEquals("Client fatal alert description", config.expectFatalAlertDescription, clientImpl.firstFatalAlertDescription); + assertEquals("Server fatal alert description", config.expectFatalAlertDescription, serverImpl.firstFatalAlertDescription); + + if (config.expectFatalAlertConnectionEnd == -1) + { + assertNull("Unexpected client exception", caught); + assertNull("Unexpected server exception", serverThread.caught); + } + } + + protected void logException(Exception e) + { + if (TlsTestConfig.DEBUG) + { + e.printStackTrace(); + } + } + + class ServerThread extends Thread + { + protected final TlsTestServerProtocol serverProtocol; + protected final TlsTestServerImpl serverImpl; + + boolean canExit = false; + Exception caught = null; + + ServerThread(TlsTestServerProtocol serverProtocol, TlsTestServerImpl serverImpl) + { + this.serverProtocol = serverProtocol; + this.serverImpl = serverImpl; + } + + synchronized void allowExit() + { + canExit = true; + this.notifyAll(); + } + + public void run() + { + try + { + serverProtocol.accept(serverImpl); + Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream()); + serverProtocol.close(); + } + catch (Exception e) + { + caught = e; + logException(caught); + } + + waitExit(); + } + + protected synchronized void waitExit() + { + while (!canExit) + { + try + { + this.wait(); + } + catch (InterruptedException e) + { + } + } + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientImpl.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientImpl.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientImpl.java 2016-12-02 22:04:06.000000000 +0000 @@ -0,0 +1,296 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.SecureRandom; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.CertificateRequest; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.ConnectionEnd; +import org.bouncycastle.tls.DefaultTlsClient; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsAuthentication; +import org.bouncycastle.tls.TlsCredentialedSigner; +import org.bouncycastle.tls.TlsCredentials; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider; +import org.bouncycastle.util.Arrays; + +class TlsTestClientImpl + extends DefaultTlsClient +{ + protected final TlsTestConfig config; + + protected int firstFatalAlertConnectionEnd = -1; + protected short firstFatalAlertDescription = -1; + + TlsTestClientImpl(TlsTestConfig config) + { + super(new BcTlsCrypto(new SecureRandom())); + + this.config = config; + } + + int getFirstFatalAlertConnectionEnd() + { + return firstFatalAlertConnectionEnd; + } + + short getFirstFatalAlertDescription() + { + return firstFatalAlertDescription; + } + + public TlsCrypto getCrypto() + { + switch (config.clientCrypto) + { + case TlsTestConfig.CRYPTO_JCA: + return new JcaTlsCryptoProvider().setProvider(new BouncyCastleProvider()).create(new SecureRandom(), new SecureRandom()); + default: + return new BcTlsCrypto(new SecureRandom()); + } + } + + public ProtocolVersion getClientVersion() + { + if (config.clientOfferVersion != null) + { + return config.clientOfferVersion; + } + + return super.getClientVersion(); + } + + public ProtocolVersion getMinimumVersion() + { + if (config.clientMinimumVersion != null) + { + return config.clientMinimumVersion; + } + + return super.getMinimumVersion(); + } + + public Hashtable getClientExtensions() throws IOException + { + Hashtable clientExtensions = super.getClientExtensions(); + if (clientExtensions != null && !config.clientSendSignatureAlgorithms) + { + clientExtensions.remove(TlsUtils.EXT_signature_algorithms); + this.supportedSignatureAlgorithms = null; + } + return clientExtensions; + } + + public boolean isFallback() + { + return config.clientFallback; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1) + { + firstFatalAlertConnectionEnd = ConnectionEnd.client; + firstFatalAlertDescription = alertDescription; + } + + if (TlsTestConfig.DEBUG) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS client raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1) + { + firstFatalAlertConnectionEnd = ConnectionEnd.server; + firstFatalAlertDescription = alertDescription; + } + + if (TlsTestConfig.DEBUG) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS client received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + } + + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + super.notifyServerVersion(serverVersion); + + if (TlsTestConfig.DEBUG) + { + System.out.println("TLS client negotiated " + serverVersion); + } + } + + public TlsAuthentication getAuthentication() + throws IOException + { + return new TlsAuthentication() + { + public void notifyServerCertificate(org.bouncycastle.tls.Certificate serverCertificate) + throws IOException + { + TlsCertificate[] chain = serverCertificate.getCertificateList(); + + if (TlsTestConfig.DEBUG) + { + System.out.println("TLS client received server certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = Certificate.getInstance(chain[i].getEncoded()); + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + + boolean isEmpty = serverCertificate == null || serverCertificate.isEmpty(); + if (isEmpty || !TlsTestUtils.isCertificateOneOf(context.getCrypto(), chain[0], + new String[]{ "x509-server.pem", "x509-server-dsa.pem", "x509-server-ecdsa.pem"})) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + } + + public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) + throws IOException + { + if (config.serverCertReq == TlsTestConfig.SERVER_CERT_REQ_NONE) + { + throw new IllegalStateException(); + } + if (config.clientAuth == TlsTestConfig.CLIENT_AUTH_NONE) + { + return null; + } + + short[] certificateTypes = certificateRequest.getCertificateTypes(); + if (certificateTypes == null || !Arrays.contains(certificateTypes, ClientCertificateType.rsa_sign)) + { + return null; + } + + Vector supportedSigAlgs = certificateRequest.getSupportedSignatureAlgorithms(); + if (supportedSigAlgs != null && config.clientAuthSigAlg != null) + { + supportedSigAlgs = new Vector(1); + supportedSigAlgs.addElement(config.clientAuthSigAlg); + } + + final TlsCredentialedSigner signerCredentials = TlsTestUtils.loadSignerCredentials(context, + supportedSigAlgs, SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem"); + + if (config.clientAuth == TlsTestConfig.CLIENT_AUTH_VALID) + { + return signerCredentials; + } + + return new TlsCredentialedSigner() + { + public byte[] generateRawSignature(byte[] hash) throws IOException + { + byte[] sig = signerCredentials.generateRawSignature(hash); + + if (config.clientAuth == TlsTestConfig.CLIENT_AUTH_INVALID_VERIFY) + { + sig = corruptBit(sig); + } + + return sig; + } + + public org.bouncycastle.tls.Certificate getCertificate() + { + org.bouncycastle.tls.Certificate cert = signerCredentials.getCertificate(); + + if (config.clientAuth == TlsTestConfig.CLIENT_AUTH_INVALID_CERT) + { + cert = corruptCertificate(context.getCrypto(), cert); + } + + return cert; + } + + public SignatureAndHashAlgorithm getSignatureAndHashAlgorithm() + { + return signerCredentials.getSignatureAndHashAlgorithm(); + } + }; + } + }; + } + + protected org.bouncycastle.tls.Certificate corruptCertificate(TlsCrypto crypto, org.bouncycastle.tls.Certificate cert) + { + TlsCertificate[] certList = cert.getCertificateList(); + try + { + certList[0] = corruptCertificateSignature(crypto, certList[0]); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + return new org.bouncycastle.tls.Certificate(certList); + } + + protected TlsCertificate corruptCertificateSignature(TlsCrypto crypto, TlsCertificate tlsCertificate) throws IOException + { + Certificate cert = Certificate.getInstance(tlsCertificate.getEncoded()); + + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(cert.getTBSCertificate()); + v.add(cert.getSignatureAlgorithm()); + v.add(corruptSignature(cert.getSignature())); + + return crypto.createCertificate(Certificate.getInstance(new DERSequence(v)).getEncoded(ASN1Encoding.DER)); + } + + protected DERBitString corruptSignature(DERBitString bs) + { + return new DERBitString(corruptBit(bs.getOctets())); + } + + protected byte[] corruptBit(byte[] bs) + { + bs = Arrays.clone(bs); + + // Flip a random bit + int bit = context.getCrypto().getSecureRandom().nextInt(bs.length << 3); + bs[bit >>> 3] ^= (1 << (bit & 7)); + + return bs; + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientProtocol.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientProtocol.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientProtocol.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientProtocol.java 2016-09-26 00:53:43.000000000 +0000 @@ -0,0 +1,30 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.bouncycastle.tls.DigitallySigned; +import org.bouncycastle.tls.TlsClientProtocol; + +class TlsTestClientProtocol extends TlsClientProtocol +{ + protected final TlsTestConfig config; + + public TlsTestClientProtocol(InputStream input, OutputStream output, TlsTestConfig config) + { + super(input, output); + + this.config = config; + } + + protected void sendCertificateVerifyMessage(DigitallySigned certificateVerify) throws IOException + { + if (certificateVerify.getAlgorithm() != null && config.clientAuthSigAlgClaimed != null) + { + certificateVerify = new DigitallySigned(config.clientAuthSigAlgClaimed, certificateVerify.getSignature()); + } + + super.sendCertificateVerifyMessage(certificateVerify); + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestConfig.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestConfig.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestConfig.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestConfig.java 2016-11-04 10:31:10.000000000 +0000 @@ -0,0 +1,141 @@ +package org.bouncycastle.tls.test; + +import java.util.Vector; + +import org.bouncycastle.tls.ConnectionEnd; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; + +public class TlsTestConfig +{ + public static final boolean DEBUG = false; + + /** + * Client does not authenticate, ignores any certificate request + */ + public static final int CLIENT_AUTH_NONE = 0; + + /** + * Client will authenticate if it receives a certificate request + */ + public static final int CLIENT_AUTH_VALID = 1; + + /** + * Client will authenticate if it receives a certificate request, with an invalid certificate + */ + public static final int CLIENT_AUTH_INVALID_CERT = 2; + + /** + * Client will authenticate if it receives a certificate request, with an invalid CertificateVerify signature + */ + public static final int CLIENT_AUTH_INVALID_VERIFY = 3; + + public static final int CRYPTO_BC = 0; + + public static final int CRYPTO_JCA = 1; + + /** + * Server will not request a client certificate + */ + public static final int SERVER_CERT_REQ_NONE = 0; + + /** + * Server will request a client certificate but receiving one is optional + */ + public static final int SERVER_CERT_REQ_OPTIONAL = 1; + + /** + * Server will request a client certificate and receiving one is mandatory + */ + public static final int SERVER_CERT_REQ_MANDATORY = 2; + + /** + * Configures the client authentication behaviour of the test client. Use CLIENT_AUTH_* constants. + */ + public int clientAuth = CLIENT_AUTH_VALID; + + /** + * If not null, and TLS 1.2 or higher is negotiated, selects a fixed signature/hash algorithm to + * be used for the CertificateVerify signature (if one is sent). + */ + public SignatureAndHashAlgorithm clientAuthSigAlg = null; + + /** + * If not null, and TLS 1.2 or higher is negotiated, selects a fixed signature/hash algorithm to + * be _claimed_ in the CertificateVerify (if one is sent), independently of what was actually used. + */ + public SignatureAndHashAlgorithm clientAuthSigAlgClaimed = null; + + public int clientCrypto = CRYPTO_BC; + + /** + * Configures the minimum protocol version the client will accept. If null, uses the library's default. + */ + public ProtocolVersion clientMinimumVersion = null; + + /** + * Configures the protocol version the client will offer. If null, uses the library's default. + */ + public ProtocolVersion clientOfferVersion = null; + + /** + * Configures whether the client will indicate version fallback via TLS_FALLBACK_SCSV. + */ + public boolean clientFallback = false; + + /** + * Configures whether a (TLS 1.2+) client will send the signature_algorithms extension in ClientHello. + */ + public boolean clientSendSignatureAlgorithms = true; + + /** + * If not null, and TLS 1.2 or higher is negotiated, selects a fixed signature/hash algorithm to + * be used for the ServerKeyExchange signature (if one is sent). + */ + public SignatureAndHashAlgorithm serverAuthSigAlg = null; + + /** + * Configures whether the test server will send a certificate request. + */ + public int serverCertReq = SERVER_CERT_REQ_OPTIONAL; + + /** + * If TLS 1.2 or higher is negotiated, configures the set of supported signature algorithms in the + * CertificateRequest (if one is sent). If null, uses a default set. + */ + public Vector serverCertReqSigAlgs = null; + + public int serverCrypto = CRYPTO_BC; + + /** + * Configures the maximum protocol version the server will accept. If null, uses the library's default. + */ + public ProtocolVersion serverMaximumVersion = null; + + /** + * Configures the minimum protocol version the server will accept. If null, uses the library's default. + */ + public ProtocolVersion serverMinimumVersion = null; + + /** + * Configures the connection end that a fatal alert is expected to be raised. Use ConnectionEnd.* constants. + */ + public int expectFatalAlertConnectionEnd = -1; + + /** + * Configures the type of fatal alert expected to be raised. Use AlertDescription.* constants. + */ + public short expectFatalAlertDescription = -1; + + public void expectClientFatalAlert(short alertDescription) + { + this.expectFatalAlertConnectionEnd = ConnectionEnd.client; + this.expectFatalAlertDescription = alertDescription; + } + + public void expectServerFatalAlert(short alertDescription) + { + this.expectFatalAlertConnectionEnd = ConnectionEnd.server; + this.expectFatalAlertDescription = alertDescription; + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerImpl.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerImpl.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerImpl.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerImpl.java 2016-12-02 22:04:06.000000000 +0000 @@ -0,0 +1,231 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.SecureRandom; +import java.util.Vector; + +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.CertificateRequest; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.ConnectionEnd; +import org.bouncycastle.tls.DefaultTlsServer; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.TlsCredentialedDecryptor; +import org.bouncycastle.tls.TlsCredentialedSigner; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider; + +class TlsTestServerImpl + extends DefaultTlsServer +{ + protected final TlsTestConfig config; + + protected int firstFatalAlertConnectionEnd = -1; + protected short firstFatalAlertDescription = -1; + + TlsTestServerImpl(TlsTestConfig config) + { + super(new BcTlsCrypto(new SecureRandom())); + + this.config = config; + } + + int getFirstFatalAlertConnectionEnd() + { + return firstFatalAlertConnectionEnd; + } + + short getFirstFatalAlertDescription() + { + return firstFatalAlertDescription; + } + + public TlsCrypto getCrypto() + { + switch (config.serverCrypto) + { + case TlsTestConfig.CRYPTO_JCA: + return new JcaTlsCryptoProvider().setProvider(new BouncyCastleProvider()).create(new SecureRandom(), new SecureRandom()); + default: + return new BcTlsCrypto(new SecureRandom()); + } + } + + protected ProtocolVersion getMaximumVersion() + { + if (config.serverMaximumVersion != null) + { + return config.serverMaximumVersion; + } + + return super.getMaximumVersion(); + } + + protected ProtocolVersion getMinimumVersion() + { + if (config.serverMinimumVersion != null) + { + return config.serverMinimumVersion; + } + + return super.getMinimumVersion(); + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1) + { + firstFatalAlertConnectionEnd = ConnectionEnd.server; + firstFatalAlertDescription = alertDescription; + } + + if (TlsTestConfig.DEBUG) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS server raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1) + { + firstFatalAlertConnectionEnd = ConnectionEnd.client; + firstFatalAlertDescription = alertDescription; + } + + if (TlsTestConfig.DEBUG) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS server received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + } + + public ProtocolVersion getServerVersion() throws IOException + { + ProtocolVersion serverVersion = super.getServerVersion(); + + if (TlsTestConfig.DEBUG) + { + System.out.println("TLS server negotiated " + serverVersion); + } + + return serverVersion; + } + + public CertificateRequest getCertificateRequest() throws IOException + { + if (config.serverCertReq == TlsTestConfig.SERVER_CERT_REQ_NONE) + { + return null; + } + + short[] certificateTypes = new short[]{ ClientCertificateType.rsa_sign, + ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign }; + + Vector serverSigAlgs = null; + if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(serverVersion)) + { + serverSigAlgs = config.serverCertReqSigAlgs; + if (serverSigAlgs == null) + { + serverSigAlgs = TlsUtils.getDefaultSupportedSignatureAlgorithms(); + } + } + + Vector certificateAuthorities = new Vector(); + certificateAuthorities.addElement(TlsTestUtils.loadBcCertificateResource("x509-ca.pem").getSubject()); + + return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities); + } + + public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCertificate) + throws IOException + { + boolean isEmpty = (clientCertificate == null || clientCertificate.isEmpty()); + + if (isEmpty != (config.clientAuth == TlsTestConfig.CLIENT_AUTH_NONE)) + { + throw new IllegalStateException(); + } + if (isEmpty && (config.serverCertReq == TlsTestConfig.SERVER_CERT_REQ_MANDATORY)) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + TlsCertificate[] chain = clientCertificate.getCertificateList(); + + if (TlsTestConfig.DEBUG) + { + System.out.println("TLS server received client certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = Certificate.getInstance(chain[i].getEncoded()); + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + + if (!isEmpty && !TlsTestUtils.isCertificateOneOf(context.getCrypto(), chain[0], + new String[]{ "x509-client.pem", "x509-client-dsa.pem", "x509-client-ecdsa.pem"})) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + } + + protected Vector getSupportedSignatureAlgorithms() + { + if (TlsUtils.isTLSv12(context) && config.serverAuthSigAlg != null) + { + Vector signatureAlgorithms = new Vector(1); + signatureAlgorithms.addElement(config.serverAuthSigAlg); + return signatureAlgorithms; + } + + return supportedSignatureAlgorithms; + } + + protected TlsCredentialedSigner getDSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, getSupportedSignatureAlgorithms(), SignatureAlgorithm.dsa, + "x509-server-dsa.pem", "x509-server-key-dsa.pem"); + } + + protected TlsCredentialedSigner getECDSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, getSupportedSignatureAlgorithms(), SignatureAlgorithm.ecdsa, + "x509-server-ecdsa.pem", "x509-server-key-ecdsa.pem"); + } + + protected TlsCredentialedDecryptor getRSAEncryptionCredentials() throws IOException + { + return TlsTestUtils.loadEncryptionCredentials(context, new String[]{ "x509-server.pem", "x509-ca.pem" }, + "x509-server-key.pem"); + } + + protected TlsCredentialedSigner getRSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, getSupportedSignatureAlgorithms(), SignatureAlgorithm.rsa, + "x509-server.pem", "x509-server-key.pem"); + } +} \ No newline at end of file diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerProtocol.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerProtocol.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerProtocol.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerProtocol.java 2016-09-26 00:53:43.000000000 +0000 @@ -0,0 +1,18 @@ +package org.bouncycastle.tls.test; + +import java.io.InputStream; +import java.io.OutputStream; + +import org.bouncycastle.tls.TlsServerProtocol; + +class TlsTestServerProtocol extends TlsServerProtocol +{ + protected final TlsTestConfig config; + + public TlsTestServerProtocol(InputStream input, OutputStream output, TlsTestConfig config) + { + super(input, output); + + this.config = config; + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestSuite.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestSuite.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestSuite.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestSuite.java 2016-10-25 06:04:03.000000000 +0000 @@ -0,0 +1,227 @@ +package org.bouncycastle.tls.test; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.HashAlgorithm; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsUtils; + +public class TlsTestSuite extends TestSuite +{ + // Make the access to constants less verbose + static abstract class C extends TlsTestConfig {} + + public TlsTestSuite() + { + super("TLS"); + } + + public static Test suite() + { + TlsTestSuite testSuite = new TlsTestSuite(); + addAllTests(testSuite, TlsTestConfig.CRYPTO_BC, TlsTestConfig.CRYPTO_BC); + addAllTests(testSuite, TlsTestConfig.CRYPTO_JCA, TlsTestConfig.CRYPTO_BC); + addAllTests(testSuite, TlsTestConfig.CRYPTO_BC, TlsTestConfig.CRYPTO_JCA); + addAllTests(testSuite, TlsTestConfig.CRYPTO_JCA, TlsTestConfig.CRYPTO_JCA); + return testSuite; + } + + private static void addAllTests(TestSuite testSuite, int clientCrypto, int serverCrypto) + { + addFallbackTests(testSuite, clientCrypto, serverCrypto); + addVersionTests(testSuite, ProtocolVersion.SSLv3, clientCrypto, serverCrypto); + addVersionTests(testSuite, ProtocolVersion.TLSv10, clientCrypto, serverCrypto); + addVersionTests(testSuite, ProtocolVersion.TLSv11, clientCrypto, serverCrypto); + addVersionTests(testSuite, ProtocolVersion.TLSv12, clientCrypto, serverCrypto); + } + + private static void addFallbackTests(TestSuite testSuite, int clientCrypto, int serverCrypto) + { + String prefix = getCryptoName(clientCrypto) + "_" + getCryptoName(serverCrypto) + "_"; + + { + TlsTestConfig c = createTlsTestConfig(ProtocolVersion.TLSv12, clientCrypto, serverCrypto); + c.clientFallback = true; + + addTestCase(testSuite, c, prefix + "FallbackGood"); + } + + { + TlsTestConfig c = createTlsTestConfig(ProtocolVersion.TLSv12, clientCrypto, serverCrypto); + c.clientOfferVersion = ProtocolVersion.TLSv11; + c.clientFallback = true; + c.expectServerFatalAlert(AlertDescription.inappropriate_fallback); + + addTestCase(testSuite, c, prefix + "FallbackBad"); + } + + { + TlsTestConfig c = createTlsTestConfig(ProtocolVersion.TLSv12, clientCrypto, serverCrypto); + c.clientOfferVersion = ProtocolVersion.TLSv11; + + addTestCase(testSuite, c, prefix + "FallbackNone"); + } + } + + private static void addVersionTests(TestSuite testSuite, ProtocolVersion version, int clientCrypto, int serverCrypto) + { + String prefix = getCryptoName(clientCrypto) + "_" + getCryptoName(serverCrypto) + "_" + + version.toString().replaceAll("[ \\.]", "") + "_"; + + { + TlsTestConfig c = createTlsTestConfig(version, clientCrypto, serverCrypto); + + addTestCase(testSuite, c, prefix + "GoodDefault"); + } + + /* + * Server only declares support for SHA1/RSA, client selects MD5/RSA. Since the client is + * NOT actually tracking MD5 over the handshake, we expect fatal alert from the client. + */ + if (TlsUtils.isTLSv12(version)) + { + TlsTestConfig c = createTlsTestConfig(version, clientCrypto, serverCrypto); + c.clientAuth = C.CLIENT_AUTH_VALID; + c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.md5, SignatureAlgorithm.rsa); + c.serverCertReqSigAlgs = TlsUtils.getDefaultRSASignatureAlgorithms(); + c.expectClientFatalAlert(AlertDescription.internal_error); + + addTestCase(testSuite, c, prefix + "BadCertificateVerifyHashAlg"); + } + + /* + * Server only declares support for SHA1/ECDSA, client selects SHA1/RSA. Since the client is + * actually tracking SHA1 over the handshake, we expect fatal alert to come from the server + * when it verifies the selected algorithm against the CertificateRequest supported + * algorithms. + */ + if (TlsUtils.isTLSv12(version)) + { + TlsTestConfig c = createTlsTestConfig(version, clientCrypto, serverCrypto); + c.clientAuth = C.CLIENT_AUTH_VALID; + c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa); + c.serverCertReqSigAlgs = TlsUtils.getDefaultECDSASignatureAlgorithms(); + c.expectServerFatalAlert(AlertDescription.illegal_parameter); + + addTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlg"); + } + + /* + * Server only declares support for SHA1/ECDSA, client signs with SHA1/RSA, but sends + * SHA1/ECDSA in the CertificateVerify. Since the client is actually tracking SHA1 over the + * handshake, and the claimed algorithm is in the CertificateRequest supported algorithms, + * we expect fatal alert to come from the server when it finds the claimed algorithm + * doesn't match the client certificate. + */ + if (TlsUtils.isTLSv12(version)) + { + TlsTestConfig c = createTlsTestConfig(version, clientCrypto, serverCrypto); + c.clientAuth = C.CLIENT_AUTH_VALID; + c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa); + c.clientAuthSigAlgClaimed = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa); + c.serverCertReqSigAlgs = TlsUtils.getDefaultECDSASignatureAlgorithms(); + c.expectServerFatalAlert(AlertDescription.decrypt_error); + + addTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlgMismatch"); + } + + { + TlsTestConfig c = createTlsTestConfig(version, clientCrypto, serverCrypto); + c.clientAuth = C.CLIENT_AUTH_INVALID_VERIFY; + c.expectServerFatalAlert(AlertDescription.decrypt_error); + + addTestCase(testSuite, c, prefix + "BadCertificateVerifySignature"); + } + + { + TlsTestConfig c = createTlsTestConfig(version, clientCrypto, serverCrypto); + c.clientAuth = C.CLIENT_AUTH_INVALID_CERT; + c.expectServerFatalAlert(AlertDescription.bad_certificate); + + addTestCase(testSuite, c, prefix + "BadClientCertificate"); + } + + { + TlsTestConfig c = createTlsTestConfig(version, clientCrypto, serverCrypto); + c.clientAuth = C.CLIENT_AUTH_NONE; + c.serverCertReq = C.SERVER_CERT_REQ_MANDATORY; + c.expectServerFatalAlert(AlertDescription.handshake_failure); + + addTestCase(testSuite, c, prefix + "BadMandatoryCertReqDeclined"); + } + + /* + * Server selects MD5/RSA for ServerKeyExchange signature, which is not in the default + * supported signature algorithms that the client sent. We expect fatal alert from the + * client when it verifies the selected algorithm against the supported algorithms. + */ + if (TlsUtils.isTLSv12(version)) + { + TlsTestConfig c = createTlsTestConfig(version, clientCrypto, serverCrypto); + c.serverAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.md5, SignatureAlgorithm.rsa); + c.expectClientFatalAlert(AlertDescription.illegal_parameter); + + addTestCase(testSuite, c, prefix + "BadServerKeyExchangeSigAlg"); + } + + /* + * Server selects MD5/RSA for ServerKeyExchange signature, which is not the default {sha1,rsa} + * implied by the absent signature_algorithms extension. We expect fatal alert from the + * client when it verifies the selected algorithm against the implicit default. + */ + if (TlsUtils.isTLSv12(version)) + { + TlsTestConfig c = createTlsTestConfig(version, clientCrypto, serverCrypto); + c.clientSendSignatureAlgorithms = false; + c.serverAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.md5, SignatureAlgorithm.rsa); + c.expectClientFatalAlert(AlertDescription.illegal_parameter); + + addTestCase(testSuite, c, prefix + "BadServerKeyExchangeSigAlg2"); + } + + { + TlsTestConfig c = createTlsTestConfig(version, clientCrypto, serverCrypto); + c.serverCertReq = C.SERVER_CERT_REQ_NONE; + + addTestCase(testSuite, c, prefix + "GoodNoCertReq"); + } + + { + TlsTestConfig c = createTlsTestConfig(version, clientCrypto, serverCrypto); + c.clientAuth = C.CLIENT_AUTH_NONE; + + addTestCase(testSuite, c, prefix + "GoodOptionalCertReqDeclined"); + } + } + + private static void addTestCase(TestSuite testSuite, TlsTestConfig config, String name) + { + testSuite.addTest(new TlsTestCase(config, name)); + } + + private static TlsTestConfig createTlsTestConfig(ProtocolVersion version, int clientCrypto, int serverCrypto) + { + TlsTestConfig c = new TlsTestConfig(); + c.clientCrypto = clientCrypto; + c.clientMinimumVersion = ProtocolVersion.SSLv3; + c.clientOfferVersion = ProtocolVersion.TLSv12; + c.serverCrypto = serverCrypto; + c.serverMaximumVersion = version; + c.serverMinimumVersion = ProtocolVersion.SSLv3; + return c; + } + + private static String getCryptoName(int crypto) + { + switch (crypto) + { + case TlsTestConfig.CRYPTO_JCA: + return "JCA"; + default: + return "BC"; + } + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java 2016-10-25 05:52:36.000000000 +0000 @@ -0,0 +1,297 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.util.Vector; + +import org.bouncycastle.asn1.pkcs.RSAPrivateKey; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import org.bouncycastle.crypto.util.PrivateKeyFactory; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.TlsContext; +import org.bouncycastle.tls.TlsCredentialedAgreement; +import org.bouncycastle.tls.TlsCredentialedDecryptor; +import org.bouncycastle.tls.TlsCredentialedSigner; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedAgreement; +import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedDecryptor; +import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedSigner; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.tls.crypto.impl.jcajce.JcaDefaultTlsCredentialedSigner; +import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto; +import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedAgreement; +import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedDecryptor; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemReader; + +public class TlsTestUtils +{ + static final byte[] rsaCertData = Base64 + .decode("MIICUzCCAf2gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBjzELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb2" + + "4gb2YgdGhlIEJvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExLzAtBgkq" + + "hkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMB4XDTEzMDIyNTA2MDIwNVoXDTEzMDIyNT" + + "A2MDM0NVowgY8xCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIw" + + "EAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWVkYmFjay1jcnlwdG" + + "9AYm91bmN5Y2FzdGxlLm9yZzBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr5YtqKmKXmEGb4Shy" + + "pL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERo0QwQjAOBgNVHQ8BAf8EBAMCBSAwEgYDVR" + + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAHU55Ncz" + + "eglREcTg54YLUlGWu2WOYWhit/iM1eeq8Kivro7q98eW52jTuMI3CI5ulqd0hYzshQKQaZ5GDzErMyM="); + + static final byte[] dudRsaCertData = Base64 + .decode("MIICUzCCAf2gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBjzELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb2" + + "4gb2YgdGhlIEJvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExLzAtBgkq" + + "hkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMB4XDTEzMDIyNTA1NDcyOFoXDTEzMDIyNT" + + "A1NDkwOFowgY8xCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIw" + + "EAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWVkYmFjay1jcnlwdG" + + "9AYm91bmN5Y2FzdGxlLm9yZzBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr5YtqKmKXmEGb4Shy" + + "pL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERo0QwQjAOBgNVHQ8BAf8EBAMCAAEwEgYDVR" + + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAJg55PBS" + + "weg6obRUKF4FF6fCrWFi6oCYSQ99LWcAeupc5BofW5MstFMhCOaEucuGVqunwT5G7/DweazzCIrSzB0="); + + static String fingerprint(org.bouncycastle.asn1.x509.Certificate c) + throws IOException + { + byte[] der = c.getEncoded(); + byte[] sha1 = sha256DigestOf(der); + byte[] hexBytes = Hex.encode(sha1); + String hex = new String(hexBytes, "ASCII").toUpperCase(); + + StringBuffer fp = new StringBuffer(); + int i = 0; + fp.append(hex.substring(i, i + 2)); + while ((i += 2) < hex.length()) + { + fp.append(':'); + fp.append(hex.substring(i, i + 2)); + } + return fp.toString(); + } + + static byte[] sha256DigestOf(byte[] input) + { + SHA256Digest d = new SHA256Digest(); + d.update(input, 0, input.length); + byte[] result = new byte[d.getDigestSize()]; + d.doFinal(result, 0); + return result; + } + + static TlsCredentialedAgreement loadAgreementCredentials(TlsContext context, String[] certResources, + String keyResource) throws IOException + { + TlsCrypto crypto = context.getCrypto(); + Certificate certificate = loadCertificateChain(crypto, certResources); + + // TODO[tls-ops] Need to have TlsCrypto construct the credentials from the certs/key (as raw data) + if (crypto instanceof BcTlsCrypto) + { + AsymmetricKeyParameter privateKey = loadBcPrivateKeyResource(keyResource); + + return new BcDefaultTlsCredentialedAgreement((BcTlsCrypto)context.getCrypto(), certificate, privateKey); + } + else + { + PrivateKey privateKey = loadJcaPrivateKeyResource(keyResource); + + return new JceDefaultTlsCredentialedAgreement((JcaTlsCrypto)context.getCrypto(), certificate, privateKey); + } + } + + static TlsCredentialedDecryptor loadEncryptionCredentials(TlsContext context, String[] certResources, + String keyResource) throws IOException + { + TlsCrypto crypto = context.getCrypto(); + Certificate certificate = loadCertificateChain(crypto, certResources); + + // TODO[tls-ops] Need to have TlsCrypto construct the credentials from the certs/key (as raw data) + if (crypto instanceof BcTlsCrypto) + { + AsymmetricKeyParameter privateKey = loadBcPrivateKeyResource(keyResource); + + return new BcDefaultTlsCredentialedDecryptor((BcTlsCrypto)crypto, certificate, privateKey); + } + else + { + PrivateKey privateKey = loadJcaPrivateKeyResource(keyResource); + + return new JceDefaultTlsCredentialedDecryptor((JcaTlsCrypto)crypto, certificate, privateKey); + } + } + + static TlsCredentialedSigner loadSignerCredentials(TlsContext context, String[] certResources, String keyResource, + SignatureAndHashAlgorithm signatureAndHashAlgorithm) throws IOException + { + TlsCrypto crypto = context.getCrypto(); + Certificate certificate = loadCertificateChain(crypto, certResources); + + // TODO[tls-ops] Need to have TlsCrypto construct the credentials from the certs/key (as raw data) + if (crypto instanceof BcTlsCrypto) + { + AsymmetricKeyParameter privateKey = loadBcPrivateKeyResource(keyResource); + + return new BcDefaultTlsCredentialedSigner(new TlsCryptoParameters(context), (BcTlsCrypto)crypto, privateKey, certificate, signatureAndHashAlgorithm); + } + else + { + PrivateKey privateKey = loadJcaPrivateKeyResource(keyResource); + + return new JcaDefaultTlsCredentialedSigner(new TlsCryptoParameters(context), (JcaTlsCrypto)crypto, privateKey, certificate, signatureAndHashAlgorithm); + } + } + + static TlsCredentialedSigner loadSignerCredentials(TlsContext context, Vector supportedSignatureAlgorithms, + short signatureAlgorithm, String certResource, String keyResource) throws IOException + { + SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; + if (supportedSignatureAlgorithms == null) + { + supportedSignatureAlgorithms = TlsUtils.getDefaultSignatureAlgorithms(signatureAlgorithm); + } + + for (int i = 0; i < supportedSignatureAlgorithms.size(); ++i) + { + SignatureAndHashAlgorithm alg = (SignatureAndHashAlgorithm) + supportedSignatureAlgorithms.elementAt(i); + if (alg.getSignature() == signatureAlgorithm) + { + // Just grab the first one we find + signatureAndHashAlgorithm = alg; + break; + } + } + + if (signatureAndHashAlgorithm == null) + { + return null; + } + + return loadSignerCredentials(context, new String[]{ certResource, "x509-ca.pem" }, + keyResource, signatureAndHashAlgorithm); + } + + static Certificate loadCertificateChain(TlsCrypto crypto, String[] resources) + throws IOException + { + TlsCertificate[] chain = new TlsCertificate[resources.length]; + for (int i = 0; i < resources.length; ++i) + { + chain[i] = loadCertificateResource(crypto, resources[i]); + } + return new Certificate(chain); + } + + static org.bouncycastle.asn1.x509.Certificate loadBcCertificateResource(String resource) + throws IOException + { + PemObject pem = loadPemResource(resource); + if (pem.getType().endsWith("CERTIFICATE")) + { + return org.bouncycastle.asn1.x509.Certificate.getInstance(pem.getContent()); + } + throw new IllegalArgumentException("'resource' doesn't specify a valid certificate"); + } + + static TlsCertificate loadCertificateResource(TlsCrypto crypto, String resource) + throws IOException + { + PemObject pem = loadPemResource(resource); + if (pem.getType().endsWith("CERTIFICATE")) + { + return crypto.createCertificate(pem.getContent()); + } + throw new IllegalArgumentException("'resource' doesn't specify a valid certificate"); + } + + static AsymmetricKeyParameter loadBcPrivateKeyResource(String resource) + throws IOException + { + PemObject pem = loadPemResource(resource); + if (pem.getType().endsWith("RSA PRIVATE KEY")) + { + RSAPrivateKey rsa = RSAPrivateKey.getInstance(pem.getContent()); + return new RSAPrivateCrtKeyParameters(rsa.getModulus(), rsa.getPublicExponent(), + rsa.getPrivateExponent(), rsa.getPrime1(), rsa.getPrime2(), rsa.getExponent1(), + rsa.getExponent2(), rsa.getCoefficient()); + } + if (pem.getType().endsWith("PRIVATE KEY")) + { + return PrivateKeyFactory.createKey(pem.getContent()); + } + throw new IllegalArgumentException("'resource' doesn't specify a valid private key"); + } + + static PrivateKey loadJcaPrivateKeyResource(String resource) + throws IOException + { + PemObject pem = loadPemResource(resource); + if (pem.getType().endsWith("RSA PRIVATE KEY")) + { + RSAPrivateKey rsa = RSAPrivateKey.getInstance(pem.getContent()); + try + { + KeyFactory keyFact = KeyFactory.getInstance("RSA", new BouncyCastleProvider()); + return keyFact.generatePrivate(new RSAPrivateCrtKeySpec(rsa.getModulus(), rsa.getPublicExponent(), + rsa.getPrivateExponent(), rsa.getPrime1(), rsa.getPrime2(), rsa.getExponent1(), + rsa.getExponent2(), rsa.getCoefficient())); + } + catch (GeneralSecurityException e) + { + throw new IllegalArgumentException("'resource' doesn't specify a valid private key", e); + } + } + if (pem.getType().endsWith("PRIVATE KEY")) + { + return null; // TODO: + } + throw new IllegalArgumentException("'resource' doesn't specify a valid private key"); + } + + static PemObject loadPemResource(String resource) + throws IOException + { + InputStream s = TlsTestUtils.class.getResourceAsStream(resource); + PemReader p = new PemReader(new InputStreamReader(s)); + PemObject o = p.readPemObject(); + p.close(); + return o; + } + + static boolean areSameCertificate(TlsCrypto crypto, TlsCertificate cert, String resource) throws IOException + { + // TODO Cache test resources? + return areSameCertificate(cert, loadCertificateResource(crypto, resource)); + } + + static boolean areSameCertificate(TlsCertificate a, TlsCertificate b) throws IOException + { + // TODO[tls-ops] Support equals on TlsCertificate? + return Arrays.areEqual(a.getEncoded(), b.getEncoded()); + } + + static boolean isCertificateOneOf(TlsCrypto crypto, TlsCertificate cert, String[] resources) throws IOException + { + for (int i = 0; i < resources.length; ++i) + { + if (areSameCertificate(crypto, cert, resources[i])) + { + return true; + } + } + return false; + } +} diff -Nru bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/UnreliableDatagramTransport.java bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/UnreliableDatagramTransport.java --- bouncycastle-1.55/tls/src/test/java/org/bouncycastle/tls/test/UnreliableDatagramTransport.java 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/java/org/bouncycastle/tls/test/UnreliableDatagramTransport.java 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,93 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.util.Random; + +import org.bouncycastle.tls.DatagramTransport; + +public class UnreliableDatagramTransport + implements DatagramTransport +{ + + private final DatagramTransport transport; + private final Random random; + private final int percentPacketLossReceiving, percentPacketLossSending; + + public UnreliableDatagramTransport(DatagramTransport transport, Random random, + int percentPacketLossReceiving, int percentPacketLossSending) + { + if (percentPacketLossReceiving < 0 || percentPacketLossReceiving > 100) + { + throw new IllegalArgumentException("'percentPacketLossReceiving' out of range"); + } + if (percentPacketLossSending < 0 || percentPacketLossSending > 100) + { + throw new IllegalArgumentException("'percentPacketLossSending' out of range"); + } + + this.transport = transport; + this.random = random; + this.percentPacketLossReceiving = percentPacketLossReceiving; + this.percentPacketLossSending = percentPacketLossSending; + } + + public int getReceiveLimit() + throws IOException + { + return transport.getReceiveLimit(); + } + + public int getSendLimit() + throws IOException + { + return transport.getSendLimit(); + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + long endMillis = System.currentTimeMillis() + waitMillis; + for (; ; ) + { + int length = transport.receive(buf, off, len, waitMillis); + if (length < 0 || !lostPacket(percentPacketLossReceiving)) + { + return length; + } + + System.out.println("PACKET LOSS (" + length + " byte packet not received)"); + + long now = System.currentTimeMillis(); + if (now >= endMillis) + { + return -1; + } + + waitMillis = (int)(endMillis - now); + } + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + if (lostPacket(percentPacketLossSending)) + { + System.out.println("PACKET LOSS (" + len + " byte packet not sent)"); + } + else + { + transport.send(buf, off, len); + } + } + + public void close() + throws IOException + { + transport.close(); + } + + private boolean lostPacket(int percentPacketLoss) + { + return percentPacketLoss > 0 && random.nextInt(100) < percentPacketLoss; + } +} diff -Nru bouncycastle-1.55/tls/src/test/javadoc/org/bouncycastle/tls/test/package.html bouncycastle-1.56/tls/src/test/javadoc/org/bouncycastle/tls/test/package.html --- bouncycastle-1.55/tls/src/test/javadoc/org/bouncycastle/tls/test/package.html 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/javadoc/org/bouncycastle/tls/test/package.html 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,5 @@ + + +Example code and test classes for the lightweight TLS API. + + diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/ca.tmpl bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/ca.tmpl --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/ca.tmpl 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/ca.tmpl 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,4 @@ +cn = BouncyCastle TLS Test CA +ca +cert_signing_key +expiration_days = 7300 diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/client.tmpl bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/client.tmpl --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/client.tmpl 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/client.tmpl 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,5 @@ +cn = BouncyCastle Test Client +tls_www_client +encryption_key +signing_key +expiration_days = 7300 diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/README.txt bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/README.txt --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/README.txt 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/README.txt 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,8 @@ +The key and certificate .pem files here were generated using GnuTLS certtool and the accompanying template files: + + certtool --generate-privkey > x509-ca-key.pem + certtool --generate-privkey > x509-client-key.pem + certtool --generate-privkey > x509-server-key.pem + certtool --generate-self-signed --load-privkey x509-ca-key.pem --template ca.tmpl --outfile x509-ca.pem + certtool --generate-certificate --load-privkey x509-client-key.pem --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem --template client.tmpl --outfile x509-client.pem + certtool --generate-certificate --load-privkey x509-server-key.pem --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem --template server.tmpl --outfile x509-server.pem diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/server.tmpl bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/server.tmpl --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/server.tmpl 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/server.tmpl 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,5 @@ +cn = BouncyCastle Test Server +tls_www_server +encryption_key +signing_key +expiration_days = 7300 diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,32 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIFegIBAAKCATEAzIc3nB+Rux7seSPAeH7Q2CkHwRKRgZRQdmL259ySG7RKZ2N7 +rSaJFhnW02OaF5/GpkkWRT/WSZQQz6wMqKf/1H7idANZ9sA4hR1HDzHNQ4Ou7h+O +Hxom+fbZzleGtMOMRdfBVYDx/vtlcv2WP1Y0gCHzHVN5854dae+OHbBI06o+HriY +3MvQgr6VuwNItGbl87ZJDWb3FZ7JAq77hyrIQGaD6HbSFtRuunr2UAhkCCRy8gEg +In0BXtXPFZSfFOGec0HiXtug4zEReSK2CVpeNyBWKw3xQuMfvRJ1SnRNoPeQ/Zk5 +FgMF/P8uXlszwY+7mri3XN+gj3yXJ+kNLIRsTG5/jo9v5qxfHKvYVwXtHLkSx/Be +5OsBsc1c8eMIszMrAiiaF2FZxMPQD97kmalzQwIDAQABAoIBMCCrbJ+R5LD+Cd8j +wye8IgHqiTmMN2p6VWFDrOrGWcmhF81sn6G907c7CLdFY/oSuc7FQpBsglRzGT2t +iWwbQbXLUBggkkCO3bhYP98ry6eAI54Xs5eWPCmWBkkmbqGgfAnf98V/o6gLYgi8 +fEEWX6vOlcsrvVbDp9vMZGgA85u+cs5sxXC8rEwQw1FW/0hfCKt62i+7hbY8bgCK +AuWV3y4B8gLxMNybvTKzeUcVhG2Bs8ZzdfP9auVILEsp6CjoqlW1QPsOJ6cJSVek +3P7k8UyY++IpajMJZ0RxD5+MgqNvrU+F9fdk0W+z8ZW/FFncmtBS/xLAxg9lCicR +qoiRGy4y/t8vKqtbMmqgev2JxSYYbE7AXD0Pp51hTRKAFASo6VdPh2/LBdXEU3uw +4cXszskCgZkA3rdK8gg8/wMXjznff/Z3a6K0c5KPGGd+SK/Q4KwND6C0ca9JouVv +PZ4qbqT++Ye1a5R3S5BSwCx13pNVmVicQQ4xQTCedaaTyhcNu3sClrK5uM4F1G7g +p5RmUFPZFWODrFpqF39wwjGaUY229+JDI++c3hUfoSNQkLqKwwu0Z4aH/0UIDMy2 +5AbX4/QMvOdosTPDDBa/9rcCgZkA6xgXtiGl4PJ7bBCAtpEZ436qFjJOnhrBoxoP +iK9wtp5alTrGYj9a0omia2Eg+JVDR2CkSsb5/98phaR0JY9dLFrk60a02YUhQAL8 +unkD0mBBRTuKejl/I31t2OTzUZOqfm7ggL6Jwy4BUkPmQbcKJg9CRs7vjF3lGmBd +EPGQi+Dj1FnBMBnqWQ5zP2kjMNQ0uHWaHlWTO9UCgZgBnTx60pp2krQqApZfHA8z +hYNfTxGgcKeWqUePSU/y7AxCwq1688TBopLWKHX8owIqnHHc51fiMrBMA69cJCtF +wW+T9GFBowpxLYeY80RKiVMVRtD+ACu6qzWuoVzybb03k5QvRWowziE7NBa+ZzJr +YUI2zdpj1Ziw49k7nqsZEP2NWRe82AL/VhlceplZCShWGHTycnvDswKBmCNkKx2m +DxzAJEhua5IQYf9XcC+LPz6Z9JCjObdwAd3cFPLmODtOIlQTmDnmE1qYzdoO+Gyx +a61TYSLXUQzeej5VKKUqrcsZOZozWOyRjzu6ddkAT6Z6xWMIXOMMBH1BZ6dE9dMr +2/1gDZ7ezekSrxpvraCPQoy1Depcm2YTl5kXL/Ul1elx3U+u1zaykzOknpMuURdD +9rhJAoGYX90aFh+SHKIc0nLBPCZA1dvvB6Nvwvynyr6pHDYFNZvsNBAqYQpLYgdY +QRiGIHeUJgdDfuQADaTQy0t7fWuWE1orvK9ywrdXCo9KlstMmSInZ5LlF54wtgpw +ivt7YjT1ewzxBJz67NdDVDLrOAo32ZTJ/iKUHoqXZGcCCWAtENzv9vRvcSJLIMYt +bUtLF3QhyUCj7/ASc+Q= +-----END RSA PRIVATE KEY----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDZzCCAh+gAwIBAgIEUqKcyzANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDExhC +b3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTMxMjA3MDM1ODAzWhcNMzMxMjAy +MDM1ODAzWjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwggFS +MA0GCSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQDMhzecH5G7Hux5I8B4ftDYKQfB +EpGBlFB2Yvbn3JIbtEpnY3utJokWGdbTY5oXn8amSRZFP9ZJlBDPrAyop//UfuJ0 +A1n2wDiFHUcPMc1Dg67uH44fGib59tnOV4a0w4xF18FVgPH++2Vy/ZY/VjSAIfMd +U3nznh1p744dsEjTqj4euJjcy9CCvpW7A0i0ZuXztkkNZvcVnskCrvuHKshAZoPo +dtIW1G66evZQCGQIJHLyASAifQFe1c8VlJ8U4Z5zQeJe26DjMRF5IrYJWl43IFYr +DfFC4x+9EnVKdE2g95D9mTkWAwX8/y5eWzPBj7uauLdc36CPfJcn6Q0shGxMbn+O +j2/mrF8cq9hXBe0cuRLH8F7k6wGxzVzx4wizMysCKJoXYVnEw9AP3uSZqXNDAgMB +AAGjQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcEADAdBgNVHQ4E +FgQU9mOvr6Pi7+4O5bKxRihqeCkyHukwDQYJKoZIhvcNAQELBQADggExAKyMiFmj +YxzjXpQBD5dvRI7xZn79vH3lo13XRBXj/sbPXDXWIv21iLfutXn/RGGsq8piPXHG +5UY3cpZR6gOq6QO1dJ91K0ViAJBFQdkhhtfbhqGY4jvj0vGO6zenG/WrjH26nCT7 +8S4L6ZoF6Y0EfQXluP50vEitTaZ6x/rung9h2JQ8rYKiRRVCA+tgBWK/CNhQ9LXy +k3GU0mKLik0AkEFS17C0NWePIPEs/Kxv9iTEFacAN9wVHjZcMYnYtWaPNX0LWV8s +2V2DMJxrmgCEcoXgJxlyEmvyqwpjB+2AiIQVIuWcwPqgBQoKHThT2zJcXV+bMhMs +6cGvaIdvPxttduQsP349GcmUIlV6zFJq+HcMjfa8hZNIkuGBpUzdRQnu1+vYTkwz +eVOPEIBZLzg9e2k= +-----END CERTIFICATE----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-dsa.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-dsa.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-dsa.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-dsa.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFmzCCBFOgAwIBAgIMVOBtHi6d3lDIPyoMMA0GCSqGSIb3DQEBCwUAMCMxITAf +BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAiGA8yMDE1MDIxNTA5NTU0 +MloYDzIwMzUwMjEwMDk1NTQyWjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVz +dCBDbGllbnQwggNHMIICOgYHKoZIzjgEATCCAi0CggEBAPvZZVsYbqUzF5Aq5JCU +GJtg9+Hgrab/2F8vnEKsYKWtKFY4BCalIbhbZ/e4VPAEV1SlV/GgmtkPVrOutThq +03j/eo98t82vismks6SMupNoyOiPqDZ+HyNEZFIQV9Ur/1D/tPBQGrD7Fbh5JOmK +QPCoo46t9Xclfm+8u8bUIhFQV4LIkug5YBm2J8wy5FeaRYno1+4Hp543oD6SkOtF +aJCp05nfiNRtaZy/LXr22UnSggG9M/zug+u3Bi2R70TI5FJq7TwYHfAlbesbLBjH +QHvE95WlFxK1YovmziBLfew5RClZ3kgj7f3SL/3WeRy2ittQaObwV27ZNj4enYAD +qkkCIQDsN/jM9mS5UDmPNRR6Wby2jvJQbHdm6yMqlFiIXVAECQKCAQEAzVrnDdM6 +kPTVALWJNYC279xIEMETimJGP39o3YXMJFlyoEzFYamJPneYlYpY4jGfuetC+jFn +HouDivtjdf/vAc+og4jaro4NcaDCjzPZBTQuvb0cFhlSbVZsit1IMv/sztJUdPcd +QKnGP+NfiChBDh8LLskvuVefEia0Ix/xwdK764zVn9oxiP5E2sKMMYnnFoVykbKU +W43sOONe+P2zOF3VTIOUngszcNDKJsXrFKZ+MtE9FvKduaXBmd0y9Pat7jFCodry +127mBeIZOKb9h3YMZCf7tQBFpX6o8JX4Ltw9hVRIsspgarli3K18WmOR+6pvAzJx +IxxiYDbo1PHMAgOCAQUAAoIBAGPk3p3hPR51sTwf2LwDrZ5Fh9tLzFoSh6ojjiR/ +FJsqwbrEEPYi4vozJOBao17qfZayMArcq7QB5eUzBaeeggvyYgYPUIUh8kBZqeLp +WtWYBXwDqNQiRSAqX0nl35SZEnyyou4kidHFW4SWSbTQw9pkM1gtP2Q7pkxabdjt +fQTJsilslKFhoV/zWYsa72YJ1GilnDLwPanaBDdpnX84W+TDS2Gy2wb0o15etOTU +Ly9EoHisZZfdwdIoAd0pJbjSHAJnudB+skL2VfPwfwxQDOTV7gh6XIe5h5bLKR3x +ruLjNx1ppcTkjKmUruTp7V+/sH9EAS8B9epiNDGwL0s8gX6jdjB0MAwGA1UdEwEB +/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDwYDVR0PAQH/BAUDAweAADAdBgNV +HQ4EFgQUGvXFed+UN0C5+YrVvcR+7cn9U6swHwYDVR0jBBgwFoAU9mOvr6Pi7+4O +5bKxRihqeCkyHukwDQYJKoZIhvcNAQELBQADggExAChl15lXRB43Oh+qIeibolYt +OBCHlUQcQcFzqK556TKNQfhWoRv1ovxbxgPokogfnLfxKdmHrb4E+aF0syxNpXGn +gBY2G7uyuKjoJnMNsxdTiS6jzps+LlgwHMYsFac0vcJATVz1U8hoR90B4pwkNkXv +ErVXj4WvHqB5a4gsqPpAslZvhxOgWLvjA+1V4HohspnMVTup3zG6frdmwLWZ+FPI +LyrEaUaWiilFl83RWuVlExhxGyfLF8u/06OJYHCUNtHT4UQavFzQMz5UwruGor7x +n8QEE84SXaQxIyWO5T2vnlxZ0+fw/0GXyJS0F0WvJ5WkK+s+y6nXZ8Hq2fDecDWn +1nw44LpnwGb//010RdtOeAHAQmGuuEf8rf1Xiw990hAYvTzM4cT9/l22vQPR3rg= +-----END CERTIFICATE----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdsa.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdsa.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdsa.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdsa.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICqzCCAWOgAwIBAgIMVOBhzQE9XhiRAUXpMA0GCSqGSIb3DQEBCwUAMCMxITAf +BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAiGA8yMDE1MDIxNTA5MDcy +NVoYDzIwMzUwMjEwMDkwNzI1WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVz +dCBDbGllbnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASWdahP6F9xwnD6eABg +2AwifyDDCw5jy5hGe+Lnvyjok/zdkw2n8lWCFdhInFC7mRcGS7aduF7dykv9C9oU +mY17o3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA8GA1Ud +DwEB/wQFAwMHgAAwHQYDVR0OBBYEFAg1z6i+u89U0RQrH9ApFWIklZrpMB8GA1Ud +IwQYMBaAFPZjr6+j4u/uDuWysUYoangpMh7pMA0GCSqGSIb3DQEBCwUAA4IBMQCL +RJIeoOlVOcseShihLd3OU7NU3tGeLDnEcwPOAPYsDN1c7V/zROTD/0W0nhSVdRfB +AyxjjDjq3J/MTf1DrouEynoAU8SZL5OnxbceX74U2WsSaJU0PAaw9zTOaKoOuTET +EVs/OMx00XXhZcu+lPFAKT3YNJKO1Rm7Sy4vnY4jnsuRsk9+D6E3CmDSnKQC/g90 +/0djrDTYpL9Lyd5zzekZPpzX7YgNfmq2X04521+3ahfq4bBMC8GRdAuon2h2FwFX ++aH9cjHHDgxPt5pHkg3Uk+Cl6KhVb2ilS0uYd4XaMPXOUOUOxRpmQ3/7YhNgyyaL +IOP+fWkbOiFbUTDaOcbBo9y8gvy7+sXuGF5k4nHXNs46Ew1gThQPFtZjqgdiEi+A +5hYd5P2j0V9L9LprzM79 +-----END CERTIFICATE----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-dsa.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-dsa.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-dsa.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-dsa.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,15 @@ +-----BEGIN PRIVATE KEY----- +MIICZQIBADCCAjoGByqGSM44BAEwggItAoIBAQD72WVbGG6lMxeQKuSQlBibYPfh +4K2m/9hfL5xCrGClrShWOAQmpSG4W2f3uFTwBFdUpVfxoJrZD1azrrU4atN4/3qP +fLfNr4rJpLOkjLqTaMjoj6g2fh8jRGRSEFfVK/9Q/7TwUBqw+xW4eSTpikDwqKOO +rfV3JX5vvLvG1CIRUFeCyJLoOWAZtifMMuRXmkWJ6NfuB6eeN6A+kpDrRWiQqdOZ +34jUbWmcvy169tlJ0oIBvTP87oPrtwYtke9EyORSau08GB3wJW3rGywYx0B7xPeV +pRcStWKL5s4gS33sOUQpWd5II+390i/91nkctorbUGjm8Fdu2TY+Hp2AA6pJAiEA +7Df4zPZkuVA5jzUUelm8to7yUGx3ZusjKpRYiF1QBAkCggEBAM1a5w3TOpD01QC1 +iTWAtu/cSBDBE4piRj9/aN2FzCRZcqBMxWGpiT53mJWKWOIxn7nrQvoxZx6Lg4r7 +Y3X/7wHPqIOI2q6ODXGgwo8z2QU0Lr29HBYZUm1WbIrdSDL/7M7SVHT3HUCpxj/j +X4goQQ4fCy7JL7lXnxImtCMf8cHSu+uM1Z/aMYj+RNrCjDGJ5xaFcpGylFuN7Djj +Xvj9szhd1UyDlJ4LM3DQyibF6xSmfjLRPRbynbmlwZndMvT2re4xQqHa8tdu5gXi +GTim/Yd2DGQn+7UARaV+qPCV+C7cPYVUSLLKYGq5YtytfFpjkfuqbwMycSMcYmA2 +6NTxzAIEIgIgC6eNrpVR96umhuvIbLz6sy2YwlGFpkK+LLJOL2GmQ4g= +-----END PRIVATE KEY----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdsa.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdsa.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdsa.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdsa.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIGUAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHoweAIBAQQhANLHM3ugk0ZTEYNx +uKn3ytAv71M61ChZAjWdC9nW1U7zoAoGCCqGSM49AwEHoUQDQgAElnWoT+hfccJw ++ngAYNgMIn8gwwsOY8uYRnvi578o6JP83ZMNp/JVghXYSJxQu5kXBku2nbhe3cpL +/QvaFJmNew== +-----END PRIVATE KEY----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,32 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIFewIBAAKCATEA2HMtdpNQ+bHX26BW/haQL42XQKpZb71KRCtUnYVZbYNTriRc +t9NIs+Ifm7clUH/hLTNE3xYHoBhG/quXl1NwJT7rq4vBZ2m2iHhV3GkV8mhfbIAn +7Uw64ehw+US/CvvNccX8gA9aCjNqRdqXEcWGwKRoW0D0kEoSXzctCqdo5h0mwcPR ++DVVMwQiFDXS+LkqhL3eF2WsebQhuFiMNi+QShO6vgWIelGvj7kjmEVttEOsRDUx +HAVtv7kMjmsi7QAyesLmyyFt7RF6BLYZZvVbjyz+Augr+MXmY2noH/ExkKfrhaLv +dql3qEA1xKNFxi7LLJ8BU1P9jJ1So7nYX4P8Cely6oq/Gee1bPdhLK61K+R/wf9i +L70krkxud7hmIlmvf0Ma0dHH3HM6dvjYaZ5/JwIDAQABAoIBMCdNzuEbwhX9Tcmj +VXihJ0CDUQZciI4KTNyRE7Xg24rP0JesIav9sVN8yamQebWi6wQ2rZhm2y6eifG/ +vfCsJY6V3NyTLaT2JL+mPk0eRe51NnKw2M81yvFvsGgLLDe13qn8viuQ3hRBHtid +Z1ZCTIRZtltvsZkr4icpEURAfwNeIsYHpW6RXK29X+TUm0Ev+oENKzGLdGTK06Xk +6RRV7a34BIdg+7qVWL4ROzKPHKIrHw/Jmg+775UekvkGfos8Cd2eseHJROhAIje1 +WQTvDzOfx3PiUW9RW9/CKUXNeRtWJVhUG8lfqdKejn1+8CxPzwqgNRJbpGvCFa0R +oDQ7+3l9ELdcA+sv9Qp2OFXIhagzXlGcC4SwMQrBiz6oK5dDqb7VEjE2igOGrRUZ +i+7G3lECgZkA2qztgn6CbUhvLEXtiUr1EwX6ZHiB1ZVWjGo8cGmS2wI4/z48Ogln +IvxnfAF7y9PYdHuNFkwbzFVRRdToLSw0bjkZVVzRodEJexvsK8LJQu2LycKOPO0n +TLuWmr030wuZyU8ebrfuvdM7qDSSzrUc28+BUkPGiWAQ4lybqppoXtgXFeOLrDvn +vp4OTkJmphM4eOSn8aPQSHECgZkA/WUAmT+/l+y6q6xo8WqEbvIkVzSfrSG3oXCd +V40oNhEPHRRDWugq19mkBOMdFWEabAKaZTl1lLfijvs0fN2RIcARVAYrg2IlJvj4 +20/muERs3yM7tX7MgFCAdApgTGBToDy2O2ANdOhgG9KCcmf1D9ZKGnum7WhQHQaD +3RV+S9LRhVyiIbeQzJxv8ejAaQVJPe99vez+TRcCgZgkLRuVzQwSvDr4HhFv9yCY +JxMHcBA6n1wUGrco+a474SBAybD5APk5BnywPSaXz9ItYwsyNyEaKrspTFGkt31t +BrE0OAjONmDVJwdpLe5Rzi6kEDWryqgHv7jonIkRtweYECi+tFsguENUTm5DGB9Q +FgIU8/VyYJwqdpuiG61Mk38uNdizg62REWDYfY+xxdg/18QY67rXYQKBmGG/UaDM +T5tKjaPlyUG/hkDKFayyNxpxVEXpjDiW0jkxEXR1OZpazxQe97+O4Mw7fhbGVkrQ +BISO/s2LJ+83BWJQlh6klqqC9LP4/P6U7vqMIrdc/w5/UGH7K+IXkphD3F6GrQFw +hyBe95wj84Awi/9E+acHphgU0jqwJbPmM6cKNxrL5hs9lZToj+Jwl7CrglprBUV7 +o4mXAoGZAJZ5BBXWeXf161K/n1hQY9dFLSYHjgv4sZMkDqyNhDpdW9HqJ2XEuscG +Gf7vaCMEV+iOHFKYBS6XMcRXg+R7VOPRvPBNwQXf1ImcQzTVlerWHwMW+y0NAubd +IIzAXPMzjcOBBiac2wg3cvBTQE29XJ/hy4Rk6qz/oWaIinYStCelCr1FR/Vw5HzE +/SYmOzdAkWM9bv3Mp/g2 +-----END RSA PRIVATE KEY----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-client.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-client.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDmjCCAlKgAwIBAgIEUqKc2jANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDExhC +b3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTMxMjA3MDM1ODE4WhcNMzMxMjAy +MDM1ODE4WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVzdCBDbGllbnQwggFS +MA0GCSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQDYcy12k1D5sdfboFb+FpAvjZdA +qllvvUpEK1SdhVltg1OuJFy300iz4h+btyVQf+EtM0TfFgegGEb+q5eXU3AlPuur +i8FnabaIeFXcaRXyaF9sgCftTDrh6HD5RL8K+81xxfyAD1oKM2pF2pcRxYbApGhb +QPSQShJfNy0Kp2jmHSbBw9H4NVUzBCIUNdL4uSqEvd4XZax5tCG4WIw2L5BKE7q+ +BYh6Ua+PuSOYRW20Q6xENTEcBW2/uQyOayLtADJ6wubLIW3tEXoEthlm9VuPLP4C +6Cv4xeZjaegf8TGQp+uFou92qXeoQDXEo0XGLsssnwFTU/2MnVKjudhfg/wJ6XLq +ir8Z57Vs92EsrrUr5H/B/2IvvSSuTG53uGYiWa9/QxrR0cfcczp2+Nhpnn8nAgMB +AAGjdjB0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDwYDVR0P +AQH/BAUDAwegADAdBgNVHQ4EFgQU+vZUEQX5t+SGCe44YgvMmiMm8NkwHwYDVR0j +BBgwFoAU9mOvr6Pi7+4O5bKxRihqeCkyHukwDQYJKoZIhvcNAQELBQADggExAI17 +s7teVt0hE9Zp40++AkK1k3/z7CCFsg+yS8+1VgFx5mU5XgNZMMgaASo1PCd9ZxFF +QPXJ18MT4YjI6kWIC5RZspsTCwCq7jyg8bw36MHTNFUTYgfgMbhWPrUHRuOq0iG4 ++wJVR6lXuHz/yaqMVNiy4yxBero7+zYiPZ+PKjEcvQxfcG+dIgptR6plNkFeZipT +VCsSrit6iuStqmR7Jpj3nxPkR+g8aAfPCeiCxrSLNJFBj5J5AGSfkBzgjF5IE/z+ +tOgcmlFwtwOAIdRn/FUr7g1FFZh+Wy7AiB7qU4EcoW1HpcXJuRuKDrTzFH7L88zu +nrv8n9XJSMDxdnP6kNwIv89HmYJWxtToO68PsATiGA6DiUUPk+FqIHqP0kgXXMSc +ODFGSlXqh4ocvtA4APE= +-----END CERTIFICATE----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-dsa.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-dsa.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-dsa.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-dsa.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFmjCCBFKgAwIBAgIMVOBtTzLTG8B9QCZvMA0GCSqGSIb3DQEBCwUAMCMxITAf +BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAiGA8yMDE1MDIxNTA5NTYz +MVoYDzIwMzUwMjEwMDk1NjMxWjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVz +dCBTZXJ2ZXIwggNGMIICOQYHKoZIzjgEATCCAiwCggEBANblGd/puZYWDvmSMCx0 +AnQQcbmjUhB3MN68/fhkKFwBPU1QhJRiSEVDG1bnsUP55EQKDs1vpiSXgy89P3aT +cagq0M+urrN97MPeKoBF8sk4o6axruspxD41OyKhW68Nnk54E+3mEPABS4yYpsuE +hFfaZhOUXdA9aUFWnPN7oo7QlI+F7la8bluz8G8j81aMsEwjBdEKg+2Mp1+33NVa +IWEegnunVEkb0vJd/WwLZYj+OgmK4fn/qqIdRXIbjeNUvpAtklE5NrARswI0RXuX +yWxPfBrQSbWk3DQvbuWbEeSUrhYY67YbpPGA5Rng8awpxdXhvzsSmT9c6BlrLfF6 +IN0CIQDWtWHaMmlAVZW9p0Dmsj70sNHJxOYWlqjCEzF7axV3fwKCAQAgFZojuX/n +leri2E9C6b8cQTof46JZeAeG2Svk8I91cnIv0iXTHfyzWLWDAYnfeuMmt+nMA6/A +1K94YI1duc3iahLa5U3fOACWJdFtL/CAFVyNth7lDeHbWTFjM5HgA76pzmAfvFtZ +pcJp1AUZZB+3coKSr6ZrMagt1HhoefGyo7JkPpsxGiFEKB79rXkFi0AEsSnbduFE +czrg8DBdXm9//yUQnTw2pphcwLZt6t6Eq3Wrpu364Dn+hJegpLfA6uOhtRJw+7xv +5jkBbvIxp1PLZEn16qmPKMs3Im4QUa2u5F0nLYUGHi01i5OSn0UWnom8EcDis/0Q +CrkyBaiMaNkkA4IBBQACggEAQob2cpVeV4uwnX8XutQLro6BkEFMhpaQLUzbI97J +Nh1OUMnW3K2KCCdhygTYfH3j2S8ys4W30zutHyhiApUdYUZKxNXXu4+NPoLwCyAE +rrN5db5QgVx8aOG/Gfmp4POMpeGKioXgOsSWpUB0uyedgT4sszq/vuZc455HiS07 +LTlaJjeIQFtKdVYXGKNWqP/WLRnjSY9IXA5hxBXvlNAVGS/M4TvBWURUJF33THTq +ioS0DYJ9Ikyn2fsgLgSRRyNU7Y5945yUhY5p6E6Njk0ZBB+2YUtB6TQhPvEY/G48 +xwH4hTZppmmfu2UIE+YlsWv10buTOT+mxU/5LjDI6RQM2KN2MHQwDAYDVR0TAQH/ +BAIwADATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHQ8BAf8EBQMDB4AAMB0GA1Ud +DgQWBBS8bllTQWk2fm2R6XSZEIoRTd6/+zAfBgNVHSMEGDAWgBT2Y6+vo+Lv7g7l +srFGKGp4KTIe6TANBgkqhkiG9w0BAQsFAAOCATEAptRUkWUT+MdvD7v733B6Gad+ +wO0G9n7Au7ZsS6NVPxc4DrozFyyhPU1uOl1koUyYQP52V1lkm1+rS7tQXm4+32iz +bLwDCYn4LD1IZQ2hTNY/g/U0oA1dp3ZOJeydZDZ9Bm1NWYeWqfHk/ZiHMdrEdIUo +7Zkg1T0ZBvmBXTUJzeDqIV0fMotFOQBJg5avyCcX56jHXbu2AmGQsQf6NoniXG37 +wY/xiPSUUmOKjAU/B4tc24ADa5r37JzlHbpOGe1nTb8AYxjyPDdjO4Um2BugKE+K +rq+NJMg8Ej2sXLOnS2FweCoIR+RXGAUUBizlHMKJ2UGQ5sCX7U86qvniMcO8CsXR +7eSkBTYpxVLENxb2zf3g22972QWuL9eHyQfuO5dca2JnenZv1aIrhTH59fX8Sw== +-----END CERTIFICATE----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdsa.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdsa.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdsa.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdsa.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICqzCCAWOgAwIBAgIMVOBhgRR/e3iAhKcbMA0GCSqGSIb3DQEBCwUAMCMxITAf +BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAiGA8yMDE1MDIxNTA5MDYw +OVoYDzIwMzUwMjEwMDkwNjA5WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVz +dCBTZXJ2ZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQzME1njDHqizStYiqf +xC45McfdqtcDFCsyik7g7JwwGBzDI3WTP5stb8gLHwGARqkaTIDr/wau+N12bIxp +Tj6Co3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud +DwEB/wQFAwMHgAAwHQYDVR0OBBYEFOaifCD845nra+asxN59LzV1LlkxMB8GA1Ud +IwQYMBaAFPZjr6+j4u/uDuWysUYoangpMh7pMA0GCSqGSIb3DQEBCwUAA4IBMQCc +wMTPTd/82sDeJkN6B8M2AFfLf/0uw01/2I/UQp2rJCJu1Yps9S1foHz939o4qJA3 ++kieb3eVE8rcMQHMv42hagj09LmYY1Unzdu8xJDMq7gDIph72Fjy5YFqb9je79C4 +JPOadGsAsG9OY9DxTKsHyiX3Mqztx1hUQ0mNiAyaFEDGus+ZhSGMdHj0uR1LqZL9 +9OgszZY0UomZfhwnPg2sHumdh+13RZ38w33b43LpCcyu7v05szquqJ8lnol8j10r +6sH1xXZmb6OJIXZeHTnX5Dv1z0/R8qyG3gyVU7sP+8KVk529Q/YjIJ8YEV1LSERW +9cKbI+8DMxVE/z01gd0YLqpPcDSfzGUTww+lMWyGQ+KDUD2bC2O4LbZhzT+ZxCPN ++mw+T5KV78wcG02PThMf +-----END CERTIFICATE----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-dsa.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-dsa.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-dsa.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-dsa.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,15 @@ +-----BEGIN PRIVATE KEY----- +MIICZAIBADCCAjkGByqGSM44BAEwggIsAoIBAQDW5Rnf6bmWFg75kjAsdAJ0EHG5 +o1IQdzDevP34ZChcAT1NUISUYkhFQxtW57FD+eRECg7Nb6Ykl4MvPT92k3GoKtDP +rq6zfezD3iqARfLJOKOmsa7rKcQ+NTsioVuvDZ5OeBPt5hDwAUuMmKbLhIRX2mYT +lF3QPWlBVpzze6KO0JSPhe5WvG5bs/BvI/NWjLBMIwXRCoPtjKdft9zVWiFhHoJ7 +p1RJG9LyXf1sC2WI/joJiuH5/6qiHUVyG43jVL6QLZJROTawEbMCNEV7l8lsT3wa +0Em1pNw0L27lmxHklK4WGOu2G6TxgOUZ4PGsKcXV4b87Epk/XOgZay3xeiDdAiEA +1rVh2jJpQFWVvadA5rI+9LDRycTmFpaowhMxe2sVd38CggEAIBWaI7l/55Xq4thP +Qum/HEE6H+OiWXgHhtkr5PCPdXJyL9Il0x38s1i1gwGJ33rjJrfpzAOvwNSveGCN +XbnN4moS2uVN3zgAliXRbS/wgBVcjbYe5Q3h21kxYzOR4AO+qc5gH7xbWaXCadQF +GWQft3KCkq+mazGoLdR4aHnxsqOyZD6bMRohRCge/a15BYtABLEp23bhRHM64PAw +XV5vf/8lEJ08NqaYXMC2berehKt1q6bt+uA5/oSXoKS3wOrjobUScPu8b+Y5AW7y +MadTy2RJ9eqpjyjLNyJuEFGtruRdJy2FBh4tNYuTkp9FFp6JvBHA4rP9EAq5MgWo +jGjZJAQiAiBhYRIk49XUmvOqUx953A+n8/KWUfyZyTHPkcIXBvW+Ig== +-----END PRIVATE KEY----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdsa.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdsa.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdsa.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdsa.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIGUAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHoweAIBAQQhALoiXMjOXuPkNVT6 +g/8PnBmXj8wEvWXCyrpO+fh9EMTdoAoGCCqGSM49AwEHoUQDQgAEMzBNZ4wx6os0 +rWIqn8QuOTHH3arXAxQrMopO4OycMBgcwyN1kz+bLW/ICx8BgEapGkyA6/8Grvjd +dmyMaU4+gg== +-----END PRIVATE KEY----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,32 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIFfAIBAAKCATEAsy/PN54P7ZkH23FHjtgZuzpyGa84+YZOM3snikem660o90Ws +TquMMtXNeAQPGAFUpu2Qxo416ogolqqtTXYJz9qsp/eDvzlNCJN7HKb5Fg28HiCc +dMx2AR03qlGkxI3WsCPxFsX83zrz8wZSvrO7jjS1/WfJW1vYme+kktYcg90+5pJ0 +5hEAIwFU/mh9KnVRVdnINCcCqdnwpA1fAPXLwqNYdRolaczaQFI1ml8YbOgCnefz +uxeSt9qz/7TkBITVvBf3AH5fUG6UezNxma85o7b1P4QJNiWGA7uwh7iABpIR7795 +Fk8ebOSUD9lZ9iqo0CzXBDAiwJe3uzSLBITlF0xbyveH+ILj7sKpa0CkV+5yZ1Cm +B426lluuBlYxbi2wfAgN8arfQtnTobl/m+ClrQIDAQABAoIBMAEZ6kKNFNbIeBqT +24dTDIUsj+DCbGPsR86wsG5FOgFRa96K0qcAS53nBAXDynKFl6igJcXs4WfLiRnN +QGcgob+cIgM6pT8rDnlZT/291pH9mD/MwnyHDwak7C7dGXrRojWQl1TGZqjJS0f5 +enaN5lUnXwROZqsxUYohFkmtj1dpjxTqUGZ0In1JdG2mDmunMgjkJ/UqtCp0QFCp +xtd1u5/913RBFC+n/CJl1+TnNQ4WNDRtkHZfJpVp+dOldQr028CJU3C5u1JB9ped +JK+dywUFlqH1Tdk2v5CQV5esvbFpXX7FIlHuId+JOwFyvkR5+7NmyQ2uAz/Yeg8K +ItdRhNQCJpYPlPH9Yb1JooEhPYrQX6oz/q2R3qiFdtc1cMZW3KCtIALZk30lW/o+ +B4EiysECgZkA1cYcdgNKy5K1O/IOyhr1eYK2us738Z3A57gC1y+m58D02dzmwacg +HKZI9Cz98L8yEyORkdxpg86xi+NIcdU15BXXioFgMI5ZSfNVBcO4rv8G/QCxEWDr +gnXe7FYuLlOKBbVXx7fJ0IXRUVbUlH5ZqE2HlFbSdPJmlaKtbxxyT7xhhWkf/MuI +hRn+MFvbXvC+JqL+FS141kECgZkA1pS74hc7H5blq0J51E8EDtgU5m770VlQKhbW +Z1D0oXVfB19DD3SX4xu22/6XlKXLlQDx4ssxVw11VIkd9WhkIrqq4U644XL5xXmf +PMsR+fG2o+Y7MY4TNy+4qcuOK17n6R2pxR4zQoVnZs/qL4s5jPKMsC76C4Udfxfh +yup0eFEJ+jPQdWYWQ6uX3UF0rA5x0Tb200aKbG0CgZkAkwaoeHoXLR//yfTXOyWD +g0jliGHkoabQEA681WcOsgJB5L1LcBETwuCS+G0hUj0NoaAq9FjVsTOtZPqyzqfH +YtGq5rXIhFzDCFt1NHvCP4ljMwsQvVUdZSLQaVd0d6Q5H2fzsYa0JNiEeB7yIhcs +btaz0tBL+ubkqzGxeuPjsvdrUyhUObd6c6DG9FeY7xlAjq43djVKEIECgZhITde9 +SDyo2UzMV1r72iAw7EimmPELSsADXqyiJZo4qXb64fOTyqK/aQBFwtTKxs8Bh076 +L6ORhLxrXsSUg7dyKFoaD0+mz/ovu1qXvolxIix7r8F0Yj5BUzgzJp7iKFmWqGMj +Q5jcKl18PETZ/lzHDJexajLhHNqij6aKnFPgktX80+bDGEIaTUCf0kWBEGDzsUSc +TmGoRQKBmQDVFQ6EAOXXNp2bMLZ78qnxmS+NZPijBDeVu1cXMYdRSBoldrtSHKUM +NFjPfesz4IRbEePK5s0vgM88QCDaspy8aLj//gh9YuqijbHOfhvMUP6MqzU/jJN7 +MDAxcGbcoFqdWTP1HB9qeX91UNRwN+2/xfO6SrLbfTvG4v/sntr8YfVYya2EuAa9 +qLk0TB3QXaoHknsz7EhRnw== +-----END RSA PRIVATE KEY----- diff -Nru bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server.pem bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server.pem --- bouncycastle-1.55/tls/src/test/resources/org/bouncycastle/tls/test/x509-server.pem 1970-01-01 00:00:00.000000000 +0000 +++ bouncycastle-1.56/tls/src/test/resources/org/bouncycastle/tls/test/x509-server.pem 2016-05-27 04:10:21.000000000 +0000 @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDmjCCAlKgAwIBAgIEUqKc4DANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDExhC +b3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTMxMjA3MDM1ODI0WhcNMzMxMjAy +MDM1ODI0WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVzdCBTZXJ2ZXIwggFS +MA0GCSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQCzL883ng/tmQfbcUeO2Bm7OnIZ +rzj5hk4zeyeKR6brrSj3RaxOq4wy1c14BA8YAVSm7ZDGjjXqiCiWqq1NdgnP2qyn +94O/OU0Ik3scpvkWDbweIJx0zHYBHTeqUaTEjdawI/EWxfzfOvPzBlK+s7uONLX9 +Z8lbW9iZ76SS1hyD3T7mknTmEQAjAVT+aH0qdVFV2cg0JwKp2fCkDV8A9cvCo1h1 +GiVpzNpAUjWaXxhs6AKd5/O7F5K32rP/tOQEhNW8F/cAfl9QbpR7M3GZrzmjtvU/ +hAk2JYYDu7CHuIAGkhHvv3kWTx5s5JQP2Vn2KqjQLNcEMCLAl7e7NIsEhOUXTFvK +94f4guPuwqlrQKRX7nJnUKYHjbqWW64GVjFuLbB8CA3xqt9C2dOhuX+b4KWtAgMB +AAGjdjB0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0P +AQH/BAUDAwegADAdBgNVHQ4EFgQUlILGBt8EzhYtlNrOPrhfwi0s6bkwHwYDVR0j +BBgwFoAU9mOvr6Pi7+4O5bKxRihqeCkyHukwDQYJKoZIhvcNAQELBQADggExAMQd +MLOlWKWJxh6IP7sRlWKjpWZyu43eSOfvEpVljW8VaRxJC8UdhpFxsXS6Ml7wEMUC +BkVNHGMxho/GJMXUBV7OsQSv0et1o45bmkN+KKisSVReSgcj6Drp/BRcUcybPtcJ +aDW1txh/suHWppVmtkIkZIF/3IR2qFekDdCLoluiEOvbNn3YjUnQLm6Eo0pBxgpb +W5MF3/19UckP1sLrs5vFk1dtDBZ/agpI9I0psv+6OsjosvrdpjIPHjwmoZ+oYtKc +4Q30vzLCVtGGyzXWBZ+Z6AbmZpJPDQtul522XKE2vE8GA3+X/RXVAZB8a86DWtzq +J1O6D+KOyA9zwe1CO+VJ5fMkjSNXY6WDzEXqyKEBP8tkkvSByiM546CXtNDbEwBe +PtYQf223mpK56XTFq4k= +-----END CERTIFICATE-----