public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Laszlo Ersek" <lersek@redhat.com>
To: jacopo.r00ta@gmail.com, devel@edk2.groups.io
Subject: Re: [edk2-devel] SSL handshake in HTTPS boot if the certificate was signed with a root certificate
Date: Tue, 31 Oct 2023 12:26:50 +0100	[thread overview]
Message-ID: <ae4b62fc-3f25-2263-4d96-36baf0c62372@redhat.com> (raw)
In-Reply-To: <7135.1698732628313427950@groups.io>

On 10/31/23 07:10, jacopo.r00ta@gmail.com wrote:
> Hi Laszlo,
>
> If I generate the certificate like
>
> /openssl req -new -nodes -x509 -days 365 -keyout server.key -out
> server.crt -config config /
>
> it works perfectly fine (with the original configuration).
>
> The problem stands with the *chain* of certificates, meaning that I
> have a root certificate (let's call it A) and sign another one for an
> IP (let's call it B). Then in the image server with such IP I set the
> certificate B, and in the VM I trust the certificate A. Unless I
> missed something, this scenario is not covered in
> https://listman.redhat.com/archives/edk2-devel-archive/2019-October/009601.html
> <https://listman.redhat.com/archives/edk2-devel-archive/2019-October/009601.html>
> .
>
> Could you confirm this is supposed to work?

Absolutely.

The expectation is not to enroll the server certificate directly in
OVMF, but to enroll the CA certificate.

In the message you link above, the certificate generation script is
embedded. There is a section that generates the CA certificate:

> openssl req -x509 -nodes \
>   -subj   /CN="$CA_NAME" \
>   -out    "$CA_NAME".crt \
>   -keyout "$TMP_CA_KEY"

and then there is a function that generates a CA-issued certificate:

> # Create a CA-issued certificate.
> # Parameters:
> # $1: Common Name
> # $2: IPv4 or IPv6 address literal, to be used in SAN; or empty string
> gencrt()
> {
>   local CN="$1"
>   local SANIP="$2"
>   local STEM
>   local EXT
>
>   if test -z "$SANIP"; then
>     # File name stem consists of Common Name only. No certificate extensions.
>     STEM=svr_$CN
>     EXT=
>   else
>     # File name stem includes Common Name and IP address literal.
>     STEM=svr_${CN}_${SANIP}
>
>     # SAN IP extension in the certificate. Rewrite the ad-hoc extensions file
>     # with the current SAN IP.
>     echo "subjectAltName=IP:$SANIP" >| "$TMP_EXT"
>     EXT="-extfile $TMP_EXT"
>   fi
>   STEM=${STEM//[:.]/_}
>
>   # Generate CSR.
>   openssl req -new -nodes \
>     -subj   /CN="$CN" \
>     -out    "$TMP_CSR" \
>     -keyout "$STEM".key
>
>   # Sign the certificate request, potentially adding the SAN IP.
>   openssl x509 -req -CAcreateserial $EXT \
>     -in       "$TMP_CSR" \
>     -out      "$STEM".crt \
>     -CA       "$CA_NAME".crt \
>     -CAkey    "$TMP_CA_KEY" \
>     -CAserial "$TMP_CA_SRL"
> }

As you see, this function does generate a Certificate Signing Request,
and then signs it with the CA certificate.

Importantly, it's the CA certificate from the first step that is
supposed to be enrolled in OVMF, then.

... However, this actually makes me notice a difference, between your
commands and mine!

(1) In your setup, you add the Subject Alt Name IP Address when
generating the CSR (note "-config config"):

  openssl req \
    -new \
    -key myip.key \
    -out myip.csr \
    -config config            <---------- this here

and then sign the CSR

  openssl x509 \
    -req \
    -in myip.csr \
    -CA rootCA.crt \
    -CAkey rootCA.key \
    -CAcreateserial \
    -out myip.crt \
    -days 500 \
    -sha256

(2) Whereas in my setup, the Subject Alt Name IP Address is NOT added
when generating the CSR (note the lack of any "-config" option):

  openssl req \
    -new \
    -nodes \
    -subj /CN="$CN" \
    -out "$TMP_CSR" \
    -keyout "$STEM".key

Instead it is added when the CA signs the CSR (see "-extfile $TMP_EXT"):

  openssl x509 \
    -req \
    -CAcreateserial \
    -extfile $TMP_EXT \                <------------- this here
    -in "$TMP_CSR" \
    -out "$STEM".crt \
    -CA "$CA_NAME".crt \
    -CAkey "$TMP_CA_KEY" \
    -CAserial "$TMP_CA_SRL"


... Yes, I think that is exactly the problem on your end. Namely, I have
now done two things:

(a) I've re-run my script from the above link. From the output files,
I've picked the *server* certificate called
"svr_192_168_124_2_192_168_124_2.crt". This is the server certificate
that has the IP address in *both* the Common Name field, *and* in the
"Subject Alt Name IP Address" field. I've dumped this certificate to
text form:

$ openssl x509 -in svr_192_168_124_2_192_168_124_2.crt -text -noout

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            1f:1a:ac:bf:ff:56:be:04:ff:fe:49:ff:e7:8b:9d:e6:0c:8d:63:dd
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = TianoCore_BZ_960_CA
        Validity
            Not Before: Oct 31 10:57:30 2023 GMT
            Not After : Nov 30 10:57:30 2023 GMT
        Subject: CN = 192.168.124.2
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    [...]
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                IP Address:192.168.124.2
            X509v3 Subject Key Identifier:
                2C:98:BC:EF:85:61:7F:05:42:8E:75:47:0B:66:80:4C:AD:3F:50:30
            X509v3 Authority Key Identifier:
                06:9A:9D:09:7C:11:63:6B:79:11:8B:B0:C1:7E:7A:7E:2C:98:32:0B
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        [...]

Please consider especially the "X509v3 extensions" section!

Under which, you will find the crucial bit

            X509v3 Subject Alternative Name:
                IP Address:192.168.124.2

(b) I have downloaded your files from
<https://drive.google.com/drive/folders/19Yo3sWZJBe43augVIFFvEXNQU8rIqGIV?usp=sharing>,
and dumped your "myip.crt" file. That is the server certificate -- the
output of the signing of the Certificate Signing Request:

$ openssl x509 -in myip.crt -text -noout

Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            73:ae:c1:b2:9f:3d:18:0f:89:07:17:d1:90:bc:cc:5b:bc:3a:bd:cb
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
        Validity
            Not Before: Oct 26 17:12:26 2023 GMT
            Not After : Mar  9 17:12:26 2025 GMT
        Subject: C = US, ST = VA, L = SomeCity, O = MyCompany, OU = MyDivision, CN = 192.168.120.1
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    [...]
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        [...]

Note that you don't have an "X509v3 extensions" section under Data;
consequently you also don't have a "X509v3 Subject Alternative Name"
section with an IP address in it.

And that's precisely why edk2 rejects the server certificate.

The openssl-x509(1ossl) manual page contains the following obscure, but
important hint -- note the second paragraph:

       -req
           By default a certificate is expected on input.  With this
           option a PKCS#10 certificate request is expected instead,
           which must be correctly self-signed.

           X.509 extensions included in the request are not copied by
           default.  X.509 extensions to be added can be specified
           using the -extfile option.

So when you run "openssl x509 -req" as quoted under (1) above, for
signing the CSR, then openssl explicitly throws away any extensions that
may be present in the Certificate Signing Request.

You need to specify the Subject Alt Name IP Address manually when
*signing* the CSR, using the "-extfile FILENAME" option, where FILENAME
is supposed to contain the line

  subjectAltName=IP:YOUR_IP_ADDRESS

... Finally, I've even dumped your Certificate Signing Request
"myip.csr":

$ openssl req -in myip.csr -text -noout

Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = US, ST = VA, L = SomeCity, O = MyCompany, OU = MyDivision, CN = 192.168.120.1
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    [...]
                Exponent: 65537 (0x10001)
        Attributes:
            (none)
            Requested Extensions:
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        [...]

As you can see, even in your CSR, the "Requested Extensions" section is
empty. The "subjectAltName" stanza of your "-config" option, when you
generate the CSR in step (1), is entirely ignored!

In summary, any X.509 extension that you want in the final server
certificate -- specifically the "Subject Alternative Name / IP Address"
one -- must be added when you *sign* the CSR with the CA key, not when
you *generate* the CSR.

Laszlo



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110399): https://edk2.groups.io/g/devel/message/110399
Mute This Topic: https://groups.io/mt/102201552/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  reply	other threads:[~2023-10-31 11:26 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-26 12:37 [edk2-devel] SSL handshake in HTTPS boot if the certificate was signed with a root certificate jacopo.r00ta
2023-10-26 16:26 ` Laszlo Ersek
2023-10-26 17:14   ` jacopo.r00ta
2023-10-26 17:19     ` jacopo.r00ta
2023-10-27 13:30       ` jacopo.r00ta
2023-10-27 14:28         ` jacopo.r00ta
2023-10-28 15:22 ` Laszlo Ersek
2023-10-31  6:10   ` jacopo.r00ta
2023-10-31 11:26     ` Laszlo Ersek [this message]
2023-11-01  6:31       ` jacopo.r00ta

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ae4b62fc-3f25-2263-4d96-36baf0c62372@redhat.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox