@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -112,6 +112,4 @@ public class CSRBuilderTest { | |||
} | |||
assertTrue(isValid); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |