2

I need my restful service support ssl in spring boot. Though the service app started successfully, I fail to access the page in Chrome(version:68.0.3440.106). The error message:ERR_SSL_VERSION_OR_CIPHER_MISMATCH

Captured image of error message: error message

pom.xml of the project:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>test</groupId>
  <artifactId>spring-restful-server-https</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

configuration file (passwords have been masked intentionally):

server.port=8443
server.ssl.key-store=classpath:shq.jks
server.ssl.key-store-password=******
server.ssl.key-password=******

Controller class:

package test.spring_restful_server_https;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @RequestMapping("/greeting")
    public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
        return new Greeting(counter.incrementAndGet(),
                            String.format(template, name));
    }
}

I use java keytool to generate the shq.jks file.
keytool command:

keytool -genkeypair -alias shq -keystore shq.jks

after execute:

keytool -list -keystore shq.jks -v

jks file infomation (my enviroment is chinese, so I translate the information and put in parenthesis):

密钥库类型(keystore type): JKS
密钥库提供方(keystore provider): SUN

您的密钥库包含 1 个条目(your keystore contains 1 entry)

别名(alias name): shq
创建日期(creation date): 2018-8-16
条目类型(entry type): PrivateKeyEntry
证书链长度(certificate chain length): 1
证书(certificate)[1]:
所有者(owner): CN=shq, OU=home, O=home, L=shanghai, ST=shanghai, C=cn
发布者(issuer): CN=shq, OU=home, O=home, L=shanghai, ST=shanghai, C=cn
序列号(serial number): 279abe96
有效期开始日期(valid from): Thu Aug 16 21:02:31 CST 2018, 截止日期(until): Wed Nov 14 21:02:31 CST 2018
证书指纹(certificate fingerprints):
         MD5: 78:E1:91:21:04:AC:38:F1:0B:30:D8:51:69:FD:BE:28
         SHA1: 8A:D5:1C:26:69:6B:5C:50:75:A6:E8:BE:66:2F:58:01:68:8F:78:1A
         SHA256: 74:0F:F1:0D:59:75:93:3B:BD:55:75:3D:F1:E8:23:17:CE:5D:C0:14:63:0D:D9:53:54:29:C2:C4:70:5A:82:C0
         签名算法名称(signature algorithm name): SHA1withDSA
         版本(version): 3

扩展(extensions):

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: AF 9F 16 35 95 36 FD 13   0C EA 19 F8 A0 D0 E3 6F  ...5.6.........o
0010: A6 CB BB EE                                        ....
]
]
Tony
  • 100
  • 13
  • what's the translation of the error message after 127.0.0.1? – zapl Aug 16 '18 at 13:47
  • Do you have any stacktrace on the server side as well? – Luiggi Mendoza Aug 16 '18 at 14:04
  • Possible duplicate of [spring boot https with valid cert get ERR\_SSL\_VERSION\_OR\_CIPHER\_MISMATCH, self signed works fine](https://stackoverflow.com/questions/39815305/spring-boot-https-with-valid-cert-get-err-ssl-version-or-cipher-mismatch-self-s) – Simon Martinelli Aug 16 '18 at 14:10
  • 1
    i think you should paste the **keytool command** to show how you generate the jks file – clevertension Aug 16 '18 at 14:19
  • there is no error stacktrace on the server side@LuiggiMendoza – Tony Aug 17 '18 at 01:35
  • I read the post which you referred, maybe there are some differences: I used jks to generate self signed certificate, however that post used certificate issued by a CA.@SimonMartinelli – Tony Aug 17 '18 at 01:41
  • Thanks for your advice. I have added the keytool command and also the detail of jks file@clevertension – Tony Aug 17 '18 at 01:41
  • it means :The website can't provide secure connection. The client and server do not support the general SSL protocol and encryption suite.@zapl – Tony Aug 17 '18 at 01:44

1 Answers1

2

keytool -genkeypair by default creates a DSA key and (selfsigned) cert, and Chrome apparently no longer supports any ciphersuites that use DSA (which SSL/TLS calls DSS for hysterical raisins). I know it did in the past, because I have used it that way, but the last time I'm sure of is quite a while ago. To fix that add -keyalg rsa. In addition if you're not using a current or recent version of Java, keytool may default to 1024 bits, which has been officially forbidden (insecure) for several years now (although I'm pretty sure Chrome doesn't yet enforce it on manually-entered certs); to be on the safe side also add -keysize 2048.

But that won't be enough. keytool -genkeypair by default creates a cert with no extensions, and particularly without the 'SAN' extension (Subject Alternative Name). SAN has been recommended for HTTPS certs since about the beginning of the century, and as of last year Chrome requires it. Fortunately recent versions of keytool can generate SAN if you add -ext SAN=type:value[,...]. But note the value(s) in SAN must match the name used to connect: if you tell the browser https://127.0.0.1:port/ as shown in your post, the cert's SAN must contain an entry for IP:127.0.0.1; an entry for a domainname like DNS:myhost.foo is a different name and DOES NOT MATCH and will not be accepted, even if myhost.foo resolves to address 127.0.0.1. SAN supports multiple entries, so you can have one or more IP(s) and/or one or more DNS(s) if you wish. (If you used another browser you could get away with omitting SAN for now, if you do make the Subject field 'CN' (Common Name) match (and it can hold only one value), but I wouldn't take a bet on how much longer.)

And in case you aren't aware, since you didn't mention it, a selfsigned cert like that generated by keytool (or by lots of other things like openssl req -new -x509 which you'll find all over the web including here on Stack) will be considered untrusted and invalid by default. You must add it to the browser's truststore before it will be trusted. Since Chrome uses the underlying system's truststore, you can do this either through Chrome or by other means that vary depending on the system which you didn't identify. If you are going to access this from other clients, as I assume you will, the truststores used by different clients usually depend on the clients, about which you didn't say anything.

ADDED: It looks like this happened in 2016; they removed all DHE keyexchange as a crude way of preventing too-small DHE aka Logjam, and the only DSA (DSS) keyexchange requires DHE. https://bugs.chromium.org/p/chromium/issues/detail?id=619194

dave_thompson_085
  • 24,048
  • 4
  • 34
  • 52
  • thanks for your answer, it does make sense to me. As to 'SAN' extension, it was new concept for me, I need some more research by myself to understand it. – Tony Aug 17 '18 at 07:06
  • 1
    Some places to start: https://stackoverflow.com/questions/7580508/getting-chrome-to-accept-self-signed-localhost-certificate https://stackoverflow.com/questions/40951939/chrome-accept-self-signed-localhost-certificate also several in serverfault and security.SX – dave_thompson_085 Aug 18 '18 at 01:39