0

I was wondering if it is possible for openssl to check the server public key size. Currently, I am connecting to the server using:

openssl s_client -connect "ip address":"port" -key client.key -cert client.crt -CAfile myCA.crt -verify 10 -verify_return_error

This is on the client side.

The server has been set with a weak server key (1024). I was hoping that there is a one-line solution for rejecting the server because of its weak server key.

schroeder
  • 123,438
  • 55
  • 284
  • 319
Sad.coder
  • 31
  • 4
  • You merely have to look at the certificate presented by the server. Is there a reason you have to do this with OpenSSL? You can do it in a browser as well. –  Feb 08 '22 at 14:15
  • Yes since I only have a shell access to the device – Sad.coder Feb 08 '22 at 14:18
  • Also, sorry for checking I understand, what about rejecting as well – Sad.coder Feb 08 '22 at 14:19
  • openssl has options like `-ssl3, -tls1, -tls1_1, -tls1_2, -tls1_3, -no_ssl3, -no_tls1, -no_tls1_1, -no_tls1_2, -no_tls1_3, etc.` which are used to allow/reject connections based on the versions of ssl/tls that the server supports. It would be nice if it had options like these to allow/reject connections based on attributes of the certificate as well, but looking at https://www.openssl.org/docs/man1.1.1/man1/s_client.html, that doesn't appear to be the case. – mti2935 Feb 08 '22 at 14:58
  • @mti2935 ahh sweet thank you, so I would have to implement feature, :'( – Sad.coder Feb 08 '22 at 15:11

2 Answers2

3

How to find the server's public key size

In order to check the size of the certificate's public key, you can use the openssl command-line tool. The commands were taken from this answer by Ari Maniatis on StackOverflow, so I would recommend upvoting his answer if it was helpful.

Essentially, there are two ways of doing it: With SNI, and without SNI. Some servers require SNI, while others don't support it.

With SNI, the command is as follows:

openssl s_client -showcerts -servername www.example.com -connect www.example.com:443 </dev/null

And without SNI, the command is as follows:

openssl s_client -showcerts -connect www.example.com:443 </dev/null

You can also use this one-liner to print the certificate information and look for the public key:

echo | openssl s_client -connect google.com:443 2>/dev/null | openssl x509 -text -noout

This will print the following output:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            02:52:16:e1:c4:99:8e:26:32:aa:5d:1d:a9:85:b4:3c
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
        Validity
            Not Before: Dec 10 00:00:00 2021 GMT
            Not After : Dec  9 23:59:59 2022 GMT
        Subject: C = US, ST = California, L = Los Angeles, O = "Verizon Digital Media Services, Inc.", CN = www.example.org
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
===>            RSA Public-Key: (2048 bit)
                Modulus:
                    00:a0:30:42:56:d7:0b:a1:11:b9:f3:0b:ec:cc:f2:
                    4c:b0:6f:13:02:6b:cf:07:f3:85:f0:42:8f:c5:54:
                    98:81:6e:7a:93:38:b6:fa:46:42:b3:5c:e6:c9:3b:
                    59:93:61:24:43:20:f5:7a:89:c9:77:ad:ff:87:c8:
                    08:db:86:f5:dc:61:75:96:5f:dc:f0:08:ca:3a:b9:
                    5e:0f:fa:37:7c:65:6a:ca:08:27:1e:9d:d8:0a:3f:
                    9e:10:db:45:25:9a:03:72:ba:f5:27:d9:b0:eb:36:
                    d4:93:39:8c:11:6c:5f:33:14:58:e5:c0:88:c5:1f:
                    7a:21:14:cc:d2:a7:5f:1c:73:1f:d9:03:20:6e:7a:
                    08:ef:17:4e:e3:be:28:c0:4f:e0:71:63:21:04:77:
                    8f:8f:4b:2b:e8:0b:a2:be:97:7e:50:6f:b8:3b:37:
                    63:7f:a4:0c:99:ff:96:a2:c3:7f:ca:7c:21:ba:fd:
                    90:d1:3f:05:a4:34:70:d6:84:8e:a5:00:dc:29:7c:
                    fd:96:cb:43:ae:39:8f:2d:c6:ad:d8:c2:1d:9b:e4:
                    5f:9c:51:9c:8b:fe:6d:49:62:5b:c7:cd:1e:18:96:
                    ce:c6:2a:07:b7:71:80:60:72:ac:57:12:00:90:43:
                    0f:23:be:a9:70:71:d6:e5:7b:85:a3:4d:05:88:21:
                    c7:23
                Exponent: 65537 (0x10001)
[...]

As you can see, example.com uses an 2048 bit RSA public key. You can also add | grep -B 1 "Public-Key" to just display the public key length and the key type. This is necessary, as EC Certificates have significantly shorter public key lengths, yet are considered just as secure.


How to reject weak public keys

Browsers will do that automatically. It seems Chrome and others automatically mark certificates with 1024 bit RSA keys as "insecure" and display a warning to the user.

  • Not directly an answer, but related: You can use the tool [testssl.sh](https://github.com/drwetter/testssl.sh) to test the SSL/TLS configuration of a server. It's way easier to use than naked openssl. –  Feb 08 '22 at 14:32
  • So, one could grep the output to find and act on the key size? – schroeder Feb 08 '22 at 14:38
  • Thank you, very much, this does help on the checking side of things but on the rejecting of the server key, I was hoping to use openssl, if not a script which has already been written, since I only have access via shell – Sad.coder Feb 08 '22 at 14:41
  • @Sad.coder How are you going to access the server? Via HTTPS or SSH? Or something else entirely? –  Feb 08 '22 at 14:50
  • 1
    @schroeder You're right. I added the grep command to my answer. You can't just grep for the key size alone, because it could be an ECC Certificate. Google, for example, uses a 256 bit ECC certificate. –  Feb 08 '22 at 14:52
  • @Sad.coder so, it looks like one could write a script, but we can't write that script for you. There is enough in this answer to construct a script. – schroeder Feb 08 '22 at 15:12
  • I should note that it is a very simple server, so the Openssl probably has some implementation of the HTTP protocol. But would I need to have access of the server? to reject the connection with it – Sad.coder Feb 08 '22 at 15:16
  • @schroeder Ya thats alright thank you :) – Sad.coder Feb 08 '22 at 15:16
  • As commented on the answer you link, `-servername` is no longer needed for SNI in 1.1.1 up (since 2018). Also, AFAICT Chrome and Firefox only warn about RSA<2048 for certs from public CAs, and all of those were required to expire by 2016 so they wouldn't be accepted anyway. – dave_thompson_085 Feb 09 '22 at 02:40
3

I want to thank @MechMK1 for providing the partial answer, and @schroeder for editing my questions and mti2935 for pointing me in the right direction, I was able to get OpenSSL to reject the server based on the server public key size. This was done through the following command:

openssl s_client -connect <ip_address>:<port> -key Client.key -cert Client.crt -CAfile myCA.crt -verify 10 -verify_return_error -cipher @SECLEVEL=2:ALL
Sad.coder
  • 31
  • 4
  • Can you comment on what part(s) did the trick? – schroeder Feb 08 '22 at 16:36
  • OP, I think you're on the right track with this, but I am skeptical that using the `-cipher` option with `openssl s_client` in this way is doing what you want as far as rejecting server certificates with RSA public keys <=1024 bits in length. The `-cipher` option allows/rejects connections based on the cipher (e.g. tls_aes_128_gcm_sha256, etc.) used. The cipher is only loosely related (at best) to the public key in the certificate. See https://security.stackexchange.com/questions/129987/can-a-ssl-certificate-dictate-protocol for more info. – mti2935 Feb 08 '22 at 17:03
  • To answer both schroeder and @mti2935 Yes mti2935 you are right on cipher suite being loosely connected but, the "-cipher @SECLEVEL=2:ALL" did do it for me schroeder, for mti2935 the SECLEVEL seems to be connected to what public keys size can be accepted as per this document https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_security_level.html#:~:text=This%20retains%20compatibility%20with%20previous%20versions%20of%20OpenSSL.&text=The%20security%20level%20corresponds%20to,than%20160%20bits%20are%20prohibited. section DEFAULT CALLBACK BEHAVIOUR – Sad.coder Feb 08 '22 at 20:01
  • The other arg which seems to work is "-auth_level 2" – Sad.coder Feb 08 '22 at 20:05
  • That's really cool! – mti2935 Feb 08 '22 at 20:10
  • SECLEVEL=2 does reject RSA/DSA<2048 (and EC<224, which practically never occurs) but it also rejects SHA1 signatures and DHE<2048 even with RSA>=2048, which are good things to reject but not what you asked for – dave_thompson_085 Feb 09 '22 at 02:54