Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AsnEncodedData.Format return empty for CRL extension in Linux #79265

Closed
t-bzhan opened this issue Dec 6, 2022 · 4 comments · Fixed by #79300
Closed

AsnEncodedData.Format return empty for CRL extension in Linux #79265

t-bzhan opened this issue Dec 6, 2022 · 4 comments · Fixed by #79300

Comments

@t-bzhan
Copy link

t-bzhan commented Dec 6, 2022

Description

AsnEncodedData.Format return empty for CRL extension in Linux with below code snippet:

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace X509Extension
{
    class Program
    {
        static void Main(string[] args)
        {            
            var x509Cert = new X509Certificate2("cert.pem");
            var crlInfo = x509Cert.Extensions["2.5.29.31"];
            var crlDistribitionPoints = new AsnEncodedData(crlInfo.Oid, crlInfo.RawData).Format(true);
            Console.WriteLine(crlDistribitionPoints);
        }
    }
}

It works as expected in Windows which outputs:

[1]CRL Distribution Point
Distribution Point Name:
Full Name:
URL=http://crl.globalsign.com/gsrsaovsslca2018.crl

However in Linux, it output nothing.

Reproduction Steps

Repo attached: X509Extension.zip

Expected behavior

The code snippet above should return the correct CRL info in Linux as in Windows

Actual behavior

It returns empty.

Regression?

No response

Known Workarounds

No response

Configuration

dotnet --info
.NET SDK (reflecting any global.json):
Version: 6.0.403
Commit: 2bc18bf292

Runtime Environment:
OS Name: ubuntu
OS Version: 18.04
OS Platform: Linux
RID: ubuntu.18.04-x64
Base Path: /usr/share/dotnet/sdk/6.0.403/

global.json file:
Not found

Host:
Version: 6.0.11
Architecture: x64
Commit: 943474c

.NET SDKs installed:
6.0.403 [/usr/share/dotnet/sdk]

Other information

No response

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Dec 6, 2022
@ghost
Copy link

ghost commented Dec 6, 2022

Tagging subscribers to this area: @dotnet/area-system-security, @vcsjones
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

AsnEncodedData.Format return empty for CRL extension in Linux with below code snippet:

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace X509Extension
{
    class Program
    {
        static void Main(string[] args)
        {            
            var x509Cert = new X509Certificate2("cert.pem");
            var crlInfo = x509Cert.Extensions["2.5.29.31"];
            var crlDistribitionPoints = new AsnEncodedData(crlInfo.Oid, crlInfo.RawData).Format(true);
            Console.WriteLine(crlDistribitionPoints);
        }
    }
}

It works as expected in Windows which outputs:

[1]CRL Distribution Point
Distribution Point Name:
Full Name:
URL=http://crl.globalsign.com/gsrsaovsslca2018.crl

However in Linux, it output nothing.

Reproduction Steps

Repo attached: X509Extension.zip

Expected behavior

The code snippet above should return the correct CRL info in Linux as in Windows

Actual behavior

It returns empty.

Regression?

No response

Known Workarounds

No response

Configuration

dotnet --info
.NET SDK (reflecting any global.json):
Version: 6.0.403
Commit: 2bc18bf292

Runtime Environment:
OS Name: ubuntu
OS Version: 18.04
OS Platform: Linux
RID: ubuntu.18.04-x64
Base Path: /usr/share/dotnet/sdk/6.0.403/

global.json file:
Not found

Host:
Version: 6.0.11
Architecture: x64
Commit: 943474c

.NET SDKs installed:
6.0.403 [/usr/share/dotnet/sdk]

Other information

No response

Author: t-bzhan
Assignees: -
Labels:

area-System.Security, untriaged

Milestone: -

@vcsjones
Copy link
Member

vcsjones commented Dec 6, 2022

On macOS this outputs the hex string, which is the behavior for "I don't have special formatting rules for this". On Windows, is works as described. On Linux, it outputs a line feed (\n), which is somewhat interesting but likely "that's what OpenSSL told us it was". I can look in to it further to see if any exception is getting swallowed internally, which can sometimes be the cause of why empty things are returned from this API.

On a different note however, I would caution using Format(..) if you intend to parse or otherwise try to interpret the data, like extract the CRL URI. Different versions of Windows, OpenSSL, and the Managed version, and even the OS locale / language can affect the output of this API which can make it tricky to parse.

You can use the System.Formats.Asn1 package to parse and read the cRLDistributionPoints extension, but it's somewhat non-trivial in effort to do. The RFC describes the ASN.1 syntax in section 4.2.1.13.

@vcsjones
Copy link
Member

vcsjones commented Dec 6, 2022

So, something is not quite right here with OpenSSL. Doing this in plain C:

#include <openssl/bio.h>
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>

int main(int argc, char *argv[])
{
    unsigned char crlDistributionPoint[56] = {
        0x30, 0x36, 0x30, 0x34, 0xa0, 0x32, 0xa0, 0x30, 0x86, 0x2e, 0x68, 0x74,
        0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x6c, 0x6f,
        0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
        0x67, 0x73, 0x72, 0x73, 0x61, 0x6f, 0x76, 0x73, 0x73, 0x6c, 0x63, 0x61,
        0x32, 0x30, 0x31, 0x38, 0x2e, 0x63, 0x72, 0x6c };
    
    ASN1_OBJECT* oid = OBJ_txt2obj("2.5.29.31", 1);
    ASN1_OCTET_STRING* contents = ASN1_OCTET_STRING_new();
    ASN1_OCTET_STRING_set(contents, crlDistributionPoint, sizeof(crlDistributionPoint));
    X509_EXTENSION* ext = X509_EXTENSION_create_by_OBJ(NULL, oid, 0, contents);
    BIO* stdoutBio = BIO_new_fp(stdout, BIO_NOCLOSE);
    X509V3_EXT_print(stdoutBio, ext, X509V3_EXT_DEFAULT, 0);
    
    X509_EXTENSION_free(ext);
    ASN1_OCTET_STRING_free(contents);
    ASN1_OBJECT_free(oid);
    
}

And compiling with

clang -L/opt/homebrew/Cellar/openssl@3/3.0.5/lib -I/opt/homebrew/Cellar/openssl@3/3.0.5/include -lcrypto -lssl main.c && ./a.out

That does correctly print:

Full Name:
  URI:http://crl.globalsign.com/gsrsaovsslca2018.crl

So this appears to be a valid issue. I'll keep looking in to it.

@vcsjones
Copy link
Member

vcsjones commented Dec 6, 2022

Okay, so the issue is our use of BIO_gets

We assume it is going to do the read all in one go. From the docs:

Usually this operation will attempt to read a line of data from the BIO of maximum length size-1

So it reads a line and writes it to a buffer, but it didn't read it to completion. We basically need to do the equivalent of "keep reading in to the buffer until there is no more data to be read"*.

*The irony of this is not lost on me.

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Dec 6, 2022
@ghost ghost removed in-pr There is an active PR which will close this issue when it is merged untriaged New issue has not been triaged by the area owner labels Dec 7, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Jan 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants