【问题标题】:Bouncy castle with spring boot带弹簧靴的充气城堡
【发布时间】:2017-12-04 12:42:56
【问题描述】:

我正在尝试通过 http 使用 Https,我使用 bouncy castle 生成 CA 证书并从 .cer 文件生成 jks 文件,使用嵌入式 tomcat 提供的属性成功启动了 Spring Boot。

问题是我总是从浏览器获得不安全的 ssl 证书(例如来自 chrome:This CA Root certificate is not trusted because it is not in the Trusted Root Certification Authorities store.),而我以编程方式使用另一个配置类添加信任库。

这是我的代码:

import org.apache.commons.codec.binary.Base64; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.cmp.CertRepMessage; import org.bouncycastle.asn1.cmp.PKIBody; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.cert.CertException; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.cmp.CMPException; import org.bouncycastle.cert.cmp.ProtectedPKIMessage; import org.bouncycastle.cert.cmp.ProtectedPKIMessageBuilder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.ContentVerifierProvider; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;

import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.security.*; import java.security.cert.X509Certificate; import java.util.Date;

public class generateService {

    private static final String BC = BouncyCastleProvider.PROVIDER_NAME;


    private static X509CertificateHolder makeV3Certificate(KeyPair subKP, String _subDN, KeyPair issKP, String _issDN)
            throws GeneralSecurityException, IOException, OperatorCreationException, CertException
    {

        PublicKey subPub  = subKP.getPublic();
        PrivateKey issPriv = issKP.getPrivate();
        PublicKey  issPub  = issKP.getPublic();

        X509v3CertificateBuilder v1CertGen = new JcaX509v3CertificateBuilder(
                new X500Name(_issDN),
                BigInteger.valueOf(System.currentTimeMillis()),
                new Date(System.currentTimeMillis()),
                new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
                new X500Name(_subDN),
                subPub);

        ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA").setProvider(BC).build(issPriv);

        X509CertificateHolder certHolder = v1CertGen.build(signer);

        ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().setProvider(BC).build(issPub);
        return certHolder;
    }


    public X509Certificate test(KeyPair kp) throws OperatorCreationException, GeneralSecurityException, CertException, IOException, CMPException {

    Provider bcProvider = new BouncyCastleProvider();
    Security.addProvider(bcProvider);
    X509CertificateHolder cert = makeV3Certificate(kp, "CN=CA", kp, "CN=CA");
    GeneralName sender = new GeneralName(new X500Name("CN=CA"));
    GeneralName recipient = new GeneralName(new X500Name("CN=CA"));

    ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BC).build(kp.getPrivate());
    ProtectedPKIMessage message = new ProtectedPKIMessageBuilder(sender, recipient)
            .setBody(new PKIBody(PKIBody.TYPE_INIT_REP, CertRepMessage.getInstance(new DERSequence(new DERSequence()))))
            .addCMPCertificate(cert)
            .build(signer);

    X509Certificate jcaCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(message.getCertificates()[0]);
    return jcaCert;
    }




    public void generateJKS() throws GeneralSecurityException, IOException, OperatorCreationException, CMPException, CertException {
        Provider bcProvider = new BouncyCastleProvider();
        Security.addProvider(bcProvider);
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        X509Certificate certificate = test(keyPair);

        final FileOutputStream os = new FileOutputStream("E:\\cert4.cer");
        os.write("-----BEGIN CERTIFICATE-----\n".getBytes("US-ASCII"));
        os.write(Base64.encodeBase64(certificate.getEncoded(), true));
        os.write("-----END CERTIFICATE-----\n".getBytes("US-ASCII"));
        os.close();

        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(null,null);
        X509Certificate[] certChain = new X509Certificate[1];
        certChain[0] = certificate;
        keyStore.setKeyEntry("myaliaskey", (Key)keyPair.getPrivate(), "secret".toCharArray(), certChain);
        OutputStream outputStream = new FileOutputStream("E:\\keystoreRSA4.jks");
        keyStore.store(outputStream, "secret".toCharArray());
        outputStream.flush();
        outputStream.close();

    }



    public static void main(String[] args) throws Exception {

        new generateService().generateJKS();
    } }

Application.properties:

server.port = 8443 server.http.port = 8080 server.ssl.key-store =  E:\\keystoreRSA4.jks server.ssl.key-password = secret server.ssl.keyAlias = myaliaskey

/**************************************************** *****************************/

import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration public class SSLConfig {


    @PostConstruct
    private void configureSSL() {
        System.setProperty("https.protocols", "TLSv1.2");
        System.setProperty("javax.net.ssl.trustStore", "E:\\keystoreRSA4.jks");
        System.setProperty("javax.net.ssl.keyStore", "E:\\keystoreRSA4.jks");
        System.setProperty("javax.net.ssl.keyStorePassword", "secret");

    } }


import org.apache.catalina.Context; import org.apache.catalina.connector.Connector; import org.apache.tomcat.util.descriptor.web.SecurityCollection; import org.apache.tomcat.util.descriptor.web.SecurityConstraint; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;

@Configuration public class TomcatConfig {
    @Value("${server.http.port}")
    private int httpPort;

    @Value("${server.port}")
    private int httpsPort;

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(initiateHttpConnector());
        return tomcat;
    }

    public Connector initiateHttpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("https");
        connector.setPort(httpPort);
        connector.setSecure(true);
        connector.setRedirectPort(httpsPort); 
        return connector;
    } }

任何帮助将不胜感激,并提前感谢您。

【问题讨论】:

  • 您的证书是自动签名的吗?如果是,浏览器总是会抱怨它。那是因为您的证书不是由认证机构生成的。
  • 感谢@RicardoZanini 的回复。该证书是由 BC 提供商自动签名的,它是自签名证书,我如何才能让浏览器接受它作为信任证书?

标签: java spring ssl spring-boot bouncycastle


【解决方案1】:

我怎样才能让浏览器接受它作为信任证书?

幸运的是,你不能。有话题讨论in this question

如果我们简单地说“HTTPS 现在可以通过自签名证书实现”,那么您的浏览器将无法区分您尝试访问的站点是否具有自签名证书,因为它应该具有自签名证书,或者因为您受到了攻击.因此,它会降低安全性。

您必须在浏览器中添加例外以接受您的证书。通常在开发过程中。对于生产用途,您必须从受信任的供应商处购买证书,例如 Verisign

要为您的浏览器添加例外,请参阅this other question

干杯!

【讨论】:

  • 感谢@Ricardo Zanin 的帮助。
猜你喜欢
  • 1970-01-01
  • 2018-02-14
  • 1970-01-01
  • 1970-01-01
  • 2013-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-27
相关资源
最近更新 更多