From 6920627ef33ba1310da98706e6775a0404a4c3fa Mon Sep 17 00:00:00 2001 From: zhanglin33 Date: Wed, 15 May 2019 16:17:54 +0800 Subject: [PATCH] add CertParser and its junitTest --- .../com/jd/blockchain/crypto/CSRBuilder.java | 18 ++- .../com/jd/blockchain/crypto/CertParser.java | 120 ++++++++++++++++++ .../jd/blockchain/crypto/CSRBuilderTest.java | 2 - .../jd/blockchain/crypto/CertParserTest.java | 38 ++++++ 4 files changed, 169 insertions(+), 9 deletions(-) diff --git a/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/CSRBuilder.java b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/CSRBuilder.java index 7ec35785..9d84a952 100644 --- a/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/CSRBuilder.java +++ b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/CSRBuilder.java @@ -1,13 +1,9 @@ package com.jd.blockchain.crypto; -import com.jd.blockchain.crypto.utils.classic.RSAUtils; -import org.bouncycastle.asn1.x500.RDN; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500NameBuilder; import org.bouncycastle.asn1.x500.style.BCStrictStyle; import org.bouncycastle.asn1.x500.style.BCStyle; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; import org.bouncycastle.operator.OperatorCreationException; @@ -47,7 +43,7 @@ public class CSRBuilder { pubKey = keyPair.getPublic(); privKey = keyPair.getPrivate(); } catch (NoSuchAlgorithmException | NoSuchProviderException e) { - throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); + throw new CryptoException(e.getMessage(), e); } } @@ -81,7 +77,7 @@ public class CSRBuilder { default: throw new CryptoException("Unsupported key algorithm[" + algoName + "] in CSR!"); } } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) { - throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); + throw new CryptoException(e.getMessage(), e); } } @@ -110,7 +106,7 @@ public class CSRBuilder { byte[] csrBytes = request.getEncoded(); result = Base64.toBase64String(csrBytes); } catch (OperatorCreationException | IOException e) { - e.printStackTrace(); + throw new CryptoException(e.getMessage(), e); } return result; @@ -123,4 +119,12 @@ public class CSRBuilder { public PrivateKey getPrivKey() { return privKey; } + + public byte[] getPubKeyBytes() { + return pubKey.getEncoded(); + } + + public byte[] getPrivKeyBytes() { + return privKey.getEncoded(); + } } diff --git a/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/CertParser.java b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/CertParser.java index 480b833c..004079c9 100644 --- a/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/CertParser.java +++ b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/CertParser.java @@ -1,5 +1,17 @@ package com.jd.blockchain.crypto; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.io.pem.PemReader; + +import javax.security.auth.x500.X500Principal; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.StringReader; +import java.security.*; +import java.security.cert.*; +import java.util.Date; + /** * @author zhanglin33 * @title: CertParser @@ -7,4 +19,112 @@ package com.jd.blockchain.crypto; * @date 2019-05-10, 15:17 */ public class CertParser { + + private PublicKey pubKey; + private String sigAlgName; + private String userName; + private String issuerName; + + private Date startTime; + private Date endTime; + + public void parse(String userCertificate, String issuerCertificate) { + + X509Certificate issuerCert = parseWithoutValidationProcess(issuerCertificate); + + // ensure that the certificate is within the validity period + try { + issuerCert.checkValidity(); + } catch (CertificateExpiredException | CertificateNotYetValidException e) { + e.printStackTrace(); + } + PublicKey issuerPubKey = issuerCert.getPublicKey(); + X500Principal issuerPrincipal = issuerCert.getSubjectX500Principal(); + + X509Certificate userCert = parseWithoutValidationProcess(userCertificate); + + // check consistency between issuer's names in userCertificate and issuerCertificate + if (!userCert.getIssuerX500Principal().equals(issuerPrincipal)) { + throw new CryptoException("Issuer in the targeted certificate is not " + + "compliance with the parent certificate!"); + } + + try { + userCert.checkValidity(); + } catch (CertificateExpiredException | CertificateNotYetValidException e) { + throw new CryptoException(e.getMessage(), e); + } + + // verify the signature in certificate with issuer's public key + try { + userCert.verify(issuerPubKey); + } catch (CertificateException | NoSuchAlgorithmException + | InvalidKeyException | NoSuchProviderException | SignatureException e) { + throw new CryptoException(e.getMessage(), e); + } + + startTime = userCert.getNotBefore(); + endTime = userCert.getNotAfter(); + + pubKey = userCert.getPublicKey(); + sigAlgName = userCert.getSigAlgName(); + issuerName = userCert.getIssuerX500Principal().getName(); + userName = userCert.getSubjectX500Principal().getName(); + } + + // certificate string in Base64 format + public X509Certificate parseWithoutValidationProcess(String certificate) { + + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + + byte[] certificateBytes; + String BEGIN = "-----BEGIN CERTIFICATE-----"; + String END = "-----END CERTIFICATE-----"; + if (!certificate.startsWith(BEGIN)) { + certificate = certificate.replaceAll("\\n", ""); + certificate = certificate.replaceAll(END, ""); + certificateBytes = Base64.decode(certificate); + } else { + try { + certificateBytes = new PemReader(new StringReader(certificate)).readPemObject().getContent(); + } catch (IOException e) { + throw new CryptoException(e.getMessage(), e); + } + } + + ByteArrayInputStream bytesIn = new ByteArrayInputStream(certificateBytes); + CertificateFactory factory; + X509Certificate cert; + try { + factory = CertificateFactory.getInstance("X509", BouncyCastleProvider.PROVIDER_NAME); + cert = (X509Certificate) factory.generateCertificate(bytesIn); + } catch (CertificateException | NoSuchProviderException e) { + throw new CryptoException(e.getMessage(), e); + } + return cert; + } + + public PublicKey getPubKey() { + return pubKey; + } + + public String getSigAlgName() { + return sigAlgName; + } + + public String getUserName() { + return userName; + } + + public String getIssuerName() { + return issuerName; + } + + public Date getStartTime() { + return startTime; + } + + public Date getEndTime() { + return endTime; + } } diff --git a/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/CSRBuilderTest.java b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/CSRBuilderTest.java index b61f3ca1..a1bb5645 100644 --- a/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/CSRBuilderTest.java +++ b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/CSRBuilderTest.java @@ -112,6 +112,4 @@ public class CSRBuilderTest { } assertTrue(isValid); } - - } diff --git a/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/CertParserTest.java b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/CertParserTest.java index 3a8ecc7a..64b55d4a 100644 --- a/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/CertParserTest.java +++ b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/CertParserTest.java @@ -1,5 +1,9 @@ package com.jd.blockchain.crypto; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + /** * @author zhanglin33 * @title: CertParserTest @@ -7,4 +11,38 @@ package com.jd.blockchain.crypto; * @date 2019-05-13, 10:05 */ public class CertParserTest { + + @Test + public void parseTest() { + CertParser parser = new CertParser(); + String issuerCert = + "-----BEGIN CERTIFICATE-----\n" + + "MIIDzzCCAregAwIBAgIKUalCR1Mt5ZSK8jANBgkqhkiG9w0BAQUFADBZMQswCQYD\n" + + "VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g\n" + + "QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDU1\n" + + "NDM2WhcNMzIwODI0MDU1NDM2WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp\n" + + "bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D\n" + + "RkNBIFRFU1QgT0NBMTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8\n" + + "jn0n8Fp6hcRdACdn1+Y6GAkC6KGgNdKyHPrmsdmhCjnd/i4qUFwnG8cp3D4lFw1G\n" + + "jmjSO5yVYbik/NbS6lbNpRgTK3fDfMFvLJpRIC+IFhG9SdAC2hwjsH9qTpL9cK2M\n" + + "bSdrC6pBdDgnbzaM9AGBF4Y6vXhj5nah4ZMsBvDp19LzXjlGuTPLuAgv9ZlWknsd\n" + + "RN70PIAmvomd10uqX4GIJ4Jq/FdKXOLZ2DNK/NhRyN6Yq71L3ham6tutXeZow5t5\n" + + "0254AnUlo1u6SeH9F8itER653o/oMLFwp+63qXAcqrHUlOQPX+JI8fkumSqZ4F2F\n" + + "t/HfVMnqdtFNCnh5+eIBAgMBAAGjgZgwgZUwHwYDVR0jBBgwFoAUdN7FjQp9EBqq\n" + + "aYNbTSHOhpvMcTgwDAYDVR0TBAUwAwEB/zA4BgNVHR8EMTAvMC2gK6AphidodHRw\n" + + "Oi8vMjEwLjc0LjQyLjMvdGVzdHJjYS9SU0EvY3JsMS5jcmwwCwYDVR0PBAQDAgEG\n" + + "MB0GA1UdDgQWBBT8C7xEmg4xoYOpgYcnHgVCxr9W+DANBgkqhkiG9w0BAQUFAAOC\n" + + "AQEAb7W0K9fZPA+JPw6lRiMDaUJ0oh052yEXreMBfoPulxkBj439qombDiFggRLc\n" + + "3g8wIEKzMOzOKXTWtnzYwN3y/JQSuJb/M1QqOEEM2PZwCxI4AkBuH6jg03RjlkHg\n" + + "/kTtuIFp9ItBCC2/KkKlp0ENfn4XgVg2KtAjZ7lpyVU0LPnhEqqUVY/xthjlCSa7\n" + + "/XHNStRxsfCTIBUWJ8n2FZyQhfV/UkMNHDBIiJR0v6C4Ai0/290WvbPEIAq+03Si\n" + + "fsHzBeA0C8lP5VzfAr6wWePaZMCpStpLaoXNcAqReKxQllElOqAhRxC5VKH+rnIQ\n" + + "OMRZvB7FRyE9IfwKApngcZbA5g==\n" + + "-----END CERTIFICATE-----"; + + String userCert = "MIIEQDCCAyigAwIBAgIFICdVYzEwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4XDTE5MDUxMDExMjAyNFoXDTIxMDUxMDExMjAyNFowcjELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTEfMB0GA1UEAxQWMDUxQGFhYWFhQFpIMDkzNTgwMjhAMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJx3F2WD1dJPzK/nRHO7d1TJ1hTjzGTmv0PQ7ECsJAh3U3BtnGTpCB+b4+JMI4LO8nHkKIBQ3P9XnF+Bf1iXdWNAQ4aWCxa2nV7lCp4w0GliPu/EMgIfmsSDUtgqbM3cr8sR8r9m1xG3gt2TIQJ+jT7sAiguU/kyNzpjaccOUIgUFa8IDFq9UeB76MXtCuhlERRZQCl47e+9w7ZoxmE7e6IZORxPp7rQWVBHlR9ntWjJfNDTm3gMP5ehP+yIZnKx1LudxkBLQxpMmspzOyH1zqx5nkKe49AfWWpDxxRvYkriyYC3aE81qLsU/bhLwNEKOju7BGDF/mhJLZUedojM0gMCAwEAAaOB9TCB8jAfBgNVHSMEGDAWgBT8C7xEmg4xoYOpgYcnHgVCxr9W+DBIBgNVHSAEQTA/MD0GCGCBHIbvKgECMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2ZjYS5jb20uY24vdXMvdXMtMTUuaHRtMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly8yMTAuNzQuNDIuMy9PQ0ExMS9SU0EvY3JsMjU2OTMuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQU5oKGaQs7Jt5Gfbt1XhFTWAySEKswHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBBQUAA4IBAQAlmPRaImZV51iKjtpMKuyLMw7dX8L0lY3tl+pVZZSxHuwsN4GCCtV0Ej50up+/6EbfL4NUTiuHVAjCroKKvb+94CrdEwdnQGM5IbGSjT78nQpeASXbIWuUwA+ImjvZOzvq/0b56AzonNzBxOMGko/bj5smM6X8jrgJ0NQppo2KNSVNC4JbuoNWI4FM94SE4DUi9H7EYl4JdOtDaDtCsq49o/A1CZyYrmoOPCgxpQQXmuB3lGq/jyoOlW2aW8uee/hYG1JJcSHLBjF0WBwdxssgbBotA5f1PebiIMSbFgjk57bd4M80hhU/rI4Hkn9pcp5R7NsX95TtyDIg90LboBnW"; + + parser.parse(userCert, issuerCert); + assertEquals("SHA1WITHRSA",parser.getSigAlgName()); + } }