1414import com .microsoft .bot .connector .authentication .OpenIdMetadataKey ;
1515import com .microsoft .bot .connector .authentication .TokenValidationParameters ;
1616import java .io .IOException ;
17- import java .math . BigInteger ;
17+ import java .io . InputStream ;
1818import java .security .GeneralSecurityException ;
1919import java .security .KeyPair ;
20- import java .security .KeyPairGenerator ;
20+ import java .security .KeyStore ;
21+ import java .security .KeyStoreException ;
2122import java .security .NoSuchAlgorithmException ;
2223import java .security .PrivateKey ;
23- import java .security .SecureRandom ;
24+ import java .security .UnrecoverableKeyException ;
2425import java .security .cert .Certificate ;
2526import java .security .cert .CertificateEncodingException ;
27+ import java .security .cert .CertificateException ;
2628import java .security .cert .X509Certificate ;
2729import java .security .interfaces .RSAPrivateKey ;
2830import java .security .interfaces .RSAPublicKey ;
3436import java .util .concurrent .CompletionException ;
3537import org .junit .Before ;
3638import org .junit .Test ;
37- import sun .security .x509 .AlgorithmId ;
38- import sun .security .x509 .CertificateAlgorithmId ;
39- import sun .security .x509 .CertificateSerialNumber ;
40- import sun .security .x509 .CertificateValidity ;
41- import sun .security .x509 .CertificateVersion ;
42- import sun .security .x509 .CertificateX509Key ;
43- import sun .security .x509 .X500Name ;
44- import sun .security .x509 .X509CertImpl ;
45- import sun .security .x509 .X509CertInfo ;
4639
40+ /**
41+ * Test Notes:
42+ *
43+ * The PKCS12 certificates were created using these steps:
44+ * https://kb.globalscape.com/Knowledgebase/11039/Generating-a-PKCS12-Private-Key-and-Public-Certificate
45+ *
46+ * For the expired cert, just specify a negative number of days in step #4.
47+ *
48+ * For both valid and expired certs, these unit tests expect the alias for both to be "bot-connector-pkcs12"
49+ * and the password to be "botframework"
50+ */
4751public class JwtTokenExtractorTests {
48- private X509Certificate validCertificate ;
49- private X509Certificate expiredCertificate ;
50- private KeyPair keyPair ;
52+ private CertInfo valid ;
53+ private CertInfo expired ;
5154
5255 @ Before
5356 public void setup () throws GeneralSecurityException , IOException {
5457 ChannelValidation .TOKENVALIDATIONPARAMETERS .validateLifetime = false ;
5558 EmulatorValidation .TOKENVALIDATIONPARAMETERS .validateLifetime = false ;
5659 GovernmentChannelValidation .TOKENVALIDATIONPARAMETERS .validateLifetime = false ;
5760
58- // create keys
59- keyPair = createKeyPair ();
60- Date now = new Date ();
61- Date from = new Date (now .getTime () - (10 * 86400000L ));
62-
63- // create expired certificate
64- Date to = new Date (now .getTime () - (9 * 86400000L ));
65- expiredCertificate = createSelfSignedCertificate (keyPair , from , to );
66-
67- // create valid certificate
68- to = new Date (now .getTime () + (9 * 86400000L ));
69- validCertificate = createSelfSignedCertificate (keyPair , from , to );
61+ valid = loadCert ("bot-connector.pkcs12" );
62+ expired = loadCert ("bot-connector-expired.pkcs12" );
7063 }
7164
7265 @ Test (expected = CompletionException .class )
7366 public void JwtTokenExtractor_WithExpiredCert_ShouldNotAllowCertSigningKey () {
7467 // this should throw a CompletionException (which contains an AuthenticationException)
7568 buildExtractorAndValidateToken (
76- expiredCertificate , keyPair .getPrivate ()
69+ expired . cert , expired . keypair .getPrivate ()
7770 ).join ();
7871 }
7972
8073 @ Test
8174 public void JwtTokenExtractor_WithValidCert_ShouldAllowCertSigningKey () {
8275 // this should not throw
8376 buildExtractorAndValidateToken (
84- validCertificate , keyPair .getPrivate ()
77+ valid . cert , valid . keypair .getPrivate ()
8578 ).join ();
8679 }
8780
@@ -92,7 +85,7 @@ public void JwtTokenExtractor_WithExpiredToken_ShouldNotAllow() {
9285 Date issuedAt = new Date (now .getTime () - 86400000L );
9386
9487 buildExtractorAndValidateToken (
95- expiredCertificate , keyPair .getPrivate (), issuedAt
88+ expired . cert , expired . keypair .getPrivate (), issuedAt
9689 ).join ();
9790 }
9891
@@ -161,45 +154,24 @@ private static TokenValidationParameters createTokenValidationParameters(X509Cer
161154 }};
162155 }
163156
164- private KeyPair createKeyPair () throws NoSuchAlgorithmException {
165- // note that this isn't allowing for a "kid" value
166- KeyPairGenerator generator = KeyPairGenerator .getInstance ("RSA" );
167- generator .initialize (2048 );
168- return generator .generateKeyPair ();
157+ private static class CertInfo {
158+ public X509Certificate cert ;
159+ public KeyPair keypair ;
169160 }
170161
171- private static X509Certificate createSelfSignedCertificate (
172- KeyPair pair , Date from , Date to
173- ) throws GeneralSecurityException , IOException {
174- String dn = "CN=Bot, OU=BotFramework, O=Microsoft, C=US" ;
175- String algorithm = "SHA256withRSA" ;
176-
177- PrivateKey privateKey = pair .getPrivate ();
178- X509CertInfo info = new X509CertInfo ();
179-
180- CertificateValidity interval = new CertificateValidity (from , to );
181- BigInteger sn = new BigInteger (64 , new SecureRandom ());
182- X500Name owner = new X500Name (dn );
183-
184- info .set (X509CertInfo .VALIDITY , interval );
185- info .set (X509CertInfo .SERIAL_NUMBER , new CertificateSerialNumber (sn ));
186- info .set (X509CertInfo .SUBJECT , owner );
187- info .set (X509CertInfo .ISSUER , owner );
188- info .set (X509CertInfo .KEY , new CertificateX509Key (pair .getPublic ()));
189- info .set (X509CertInfo .VERSION , new CertificateVersion (CertificateVersion .V3 ));
190- AlgorithmId algo = new AlgorithmId (AlgorithmId .sha256WithRSAEncryption_oid );
191- info .set (X509CertInfo .ALGORITHM_ID , new CertificateAlgorithmId (algo ));
192-
193- // Sign the cert to identify the algorithm that's used.
194- X509CertImpl cert = new X509CertImpl (info );
195- cert .sign (privateKey , algorithm );
196-
197- // Update the algorithm, and resign.
198- algo = (AlgorithmId )cert .get (X509CertImpl .SIG_ALG );
199- info .set (CertificateAlgorithmId .NAME + "." + CertificateAlgorithmId .ALGORITHM , algo );
200- cert = new X509CertImpl (info );
201- cert .sign (privateKey , algorithm );
202- return cert ;
162+ private static CertInfo loadCert (String pkcs12File )
163+ throws KeyStoreException , CertificateException , NoSuchAlgorithmException , IOException ,
164+ UnrecoverableKeyException {
165+ InputStream fis = ClassLoader .getSystemResourceAsStream (pkcs12File );
166+ KeyStore p12 = KeyStore .getInstance ("pkcs12" );
167+ p12 .load (fis , "botframework" .toCharArray ());
168+
169+ return new CertInfo () {{
170+ cert = (X509Certificate ) p12 .getCertificate ("bot-connector-pkcs12" );
171+ keypair = new KeyPair (cert .getPublicKey (),
172+ (PrivateKey ) p12 .getKey ("bot-connector-pkcs12" , "botframework" .toCharArray ())
173+ );
174+ }};
203175 }
204176
205177 private static String encodeCertificate (Certificate certificate ) {
0 commit comments