How to extract the curve_name from X509 ECC cert

Greetings Rustaceans, sending peace.

I am a beginner at Rust Programming. I am coming from C with a some crypto experience. Rust is a very impressive language, loving the journey so far. Here is my question.

**How do I extract the ECC curve-name from a X509 ECC certificate using the OpenSSL Crate? **

I have uploaded the example code (below) that I have written to pull out all that can from a PEM encoded cert. What I am after is a way to get the strings:

ASN1 OID: secp384r1

You can see these when you decode the cert using OpenSSL's x509 command: openssl x509 -in AffirmTrust_Premium_ECC.crt -inform PEM -noout -text

Based on the doc for the OpenSSL crate rust-openssl, there is indeed a function called curve_name within the EcGroupRef trait, but I am not sure how to make the connection. I was thinking that subject_key_id in the example (below) that I have uploaded is the OID that is needed, and all I have to do is convert it to a string? Anyhow, any help/pointers will be welcomed.


use std::{

use openssl::{

use hex::{self};

fn main() {
    // let file_data = std::fs::read(file)?;
    let file_data = include_bytes!("AffirmTrust_Premium_ECC.crt");
    let csv_data_cert_string = parse_cert_with_openssl(file_data).expect("Problem Parsing Cert");

    println!("\ncsv_data_cert_string:\n {}", csv_data_cert_string);


This cert file used in this example is taken from
/usr/share/ca-certificates/mozilla/AffirmTrust_Premium_ECC.crt .  I
just copied in from that folder into this current dir.  So just in
case you want to run this example and do not have it, I have inlcude
it here


fn parse_cert_with_openssl(cert_data: &[u8]) -> Result<String, std::io::Error> {

    let x509 = X509::from_pem(&cert_data)?;
    let version = x509.version().to_string();
    let subject = x509.subject_name();
    let subject_key_id = x509.subject_key_id().unwrap();
    let issuer = x509.issuer_name();
    let signature_algorithm = x509.signature_algorithm().object().to_string();
    let not_before = x509.not_before().to_string();
    let not_after =  x509.not_after().to_string();
    let pubkey = x509.public_key()?;
    let pubkey_len = pubkey.bits();
    let digest = x509.digest(MessageDigest::sha256())?;
    println!("Complete X509 decoded cert: {:?}", x509);
    println!("X509 version: {}", version);
    println!("X509 Public Key: {:?}", pubkey);
    println!("X509 Public Key Length: {}", pubkey_len);
    println!("X509 signature_algorithm: {:#?}", signature_algorithm);
    println!("X509 Subject Key ID: {:?}", subject_key_id.as_slice());
    println!("X509 Subject: {:?}", subject);
    println!("X509 Issuer: {:?}", issuer);
    println!("X509 validity: {} to {}", not_before, not_after);
    // How do I print bytes to hex without needing the hex crate?
    // let digest_string: String = format!("{:x}", digest.into());
    println!("X509 Digest: {:#?}", hex::encode(digest));
    let mut w = Vec::new();
    write!(&mut w, "{},", hex::encode(digest))?;
    write!(&mut w, "{},", version)?;
    write!(&mut w, "{},", pubkey_len)?;
    write!(&mut w, "{:?},", signature_algorithm)?;
    write!(&mut w, "{:?},", subject)?;
    write!(&mut w, "{:?},", issuer)?;
    write!(&mut w, "{} to {}", not_before, not_after)?;

    let csv_data_cert_string = String::from_utf8(w).unwrap();
    // println!("\nReturning from parse_cert() csv_data_cert_string:\n {}", csv_data_cert_string);


Try this:

let key = EcKey::<Public>::try_from(pubkey)?;

The NIST curve name seems to be obtained from openssl's EC_curve_nid2nist() function but it doesn't look like rust-openssl is using it. You can call it directly using ffi:

use std::ffi::{c_int, c_char, CStr};
extern "C" {
    fn EC_curve_nid2nist(nid: c_int) -> *const c_char;

fn curve_nist_name(curve: Nid) -> Option<&'static str> {
    unsafe {
        let ptr = EC_curve_nid2nist(curve.as_raw());
        if !ptr.is_null() {
        } else {

println!("{}", curve_nist_name(;

Thanks for that, I will try as suggested and get back to you. I have been wondering how to call the OpenSSL APIs directly, so you have given much with this reply.

No problem. check out the FFI guide if you want to call more complex APIs.

Wow, It works, you are a genius at this! Thank you!

Code changes and output

    let pubkey = x509.public_key()?;
    let key = EcKey::<Public>::try_from(pubkey.clone())?;
    println!("curve_name: {}", curve_nist_name(;
$ ./target/debug/parse-cert-example 
curve_name: P-384

If you have time to for these followup questions, I would love that.

  1. What is the difference between the 2 pubkey in the following. That is: is 2nd one merely a sort of type casting?:
    let pubkey = x509.public_key()?; // it seems this is more of key type than the actual key
    let key = EcKey::<Public>::try_from(pubkey.clone())?;

  2. How do I also get the ASN1 OID: secp384r1 ? It this related to the subject_key_id?

  3. let digest_hex = format!("{:x}", digest)); // trying to convert byes to hex, but too many compiler errors, ended up using the hex crate instead.

  1. Check openssl's docs, PKey is a generic asymmetric key while EcKey is specifically an elliptic curve key
  2. That's the long_name() from my first example.
  3. {:x?} works but for proper hex formatting use a crate

Now it all starting to make sense, thanks again.

One Love!