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

Parsing extensions as othername #2264

Open
sethcall opened this issue Jul 11, 2024 · 1 comment
Open

Parsing extensions as othername #2264

sethcall opened this issue Jul 11, 2024 · 1 comment

Comments

@sethcall
Copy link

I'm using the rust-openssl crate to parse a X509 certificate. I'm trying to get at a Subject Alternate Name field on that cert.

For the example cert snippet (from openssl x509 -text)

...
 X509v3 Subject Alternative Name:
                othername: UPN::myuser@somedomain.com
...

Take the following example code:

use std::fmt::Pointer;
use openssl::x509::{GeneralName, X509};
fn main() {
    static SOME_PEM: &str = "spikes/x509_parser/cert.pem";
    let data = std::fs::read(SOME_PEM).expect("Could not read file");
    let cert = X509::from_pem(data.as_slice()).expect("Could not load cert");

    let sans = cert.subject_alt_names().unwrap();

    println("SAN count: {}", b.len());

    for entry in  &b {
        # all of the below (unsurprisingly) result in None
        # entry.ipaddress() 
        # entry.email() 
        # entry.dnsname() 
    }
 }

There is no entry.othername(); as I've dug into the code base, I've started to understand why. In openssl-sys/src/x509v3.rs, you can see:

#[repr(C)]
pub struct GENERAL_NAME {
    pub type_: c_int,
    // FIXME should be a union
    pub d: *mut c_void,
}

So I find the definition of GENERAL_NAME in C, and it's like this:

...
typedef struct otherName_st {
    ASN1_OBJECT *type_id;
    ASN1_TYPE *value;
} OTHERNAME;
...
typedef struct GENERAL_NAME_st {
# define GEN_OTHERNAME   0
# define GEN_EMAIL       1
# define GEN_DNS         2
# define GEN_X400        3
# define GEN_DIRNAME     4
# define GEN_EDIPARTY    5
# define GEN_URI         6
# define GEN_IPADD       7
# define GEN_RID         8
    int type;
    union {
        char *ptr;
        OTHERNAME *otherName;   /* otherName */
        ASN1_IA5STRING *rfc822Name;
        ASN1_IA5STRING *dNSName;
        ASN1_TYPE *x400Address;
        X509_NAME *directoryName;
        EDIPARTYNAME *ediPartyName;
        ASN1_IA5STRING *uniformResourceIdentifier;
        ASN1_OCTET_STRING *iPAddress;
        ASN1_OBJECT *registeredID;
        /* Old names */
        ASN1_OCTET_STRING *ip;  /* iPAddress */
        X509_NAME *dirn;        /* dirn */
        ASN1_IA5STRING *ia5;    /* rfc822Name, dNSName,
                                 * uniformResourceIdentifier */
        ASN1_OBJECT *rid;       /* registeredID */
        ASN1_TYPE *other;       /* x400Address */
    } d;
} GENERAL_NAME;

Right, so I see now why there are only helpers for dnsname, ipaddress, etc... these are easy to parse as a single object; they are not nested / custom objects. On the other hand, OTHERNAME is 'custom', so I don't think you can wrap this. Instead, I think we have to just provide a the ASNI1_OBJECT type_id (oid), and the ASN1_TYPE as a byte array ([u8]).

Anyway, I was interested in doing this, but I had some immediate questions, like, where does src\x509v3.rs come from... is this created by hand?

Ultimately, if this is done correctly,. I think someone can parse OTHERNAME like in this code example; i.e., give the user the raw data; they still have to parse on their own outside of this library. https://stackoverflow.com/a/25049371

@Will5
Copy link

Will5 commented Sep 12, 2024

I am looking for a similar solution as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants