hjiayz / p12

Other
8 stars 11 forks source link

Seems to construct an invalid pkcs12 file #3

Open nicklan opened 3 years ago

nicklan commented 3 years ago

I'm trying to convert a pem key/cert into a pkcs12 (so the equivalent of openssl pkcs12 -export -out client.pfx -inkey client_key.pem -in client_crt.pem).

I'm using the pem crate to get the der encoded data.

Here's the code I'm using to convert:

fn convert<P: AsRef<Path>>(key: P, cert: P, out: P) -> Result<(), Box<dyn std::error::Error>> {
    let mut key_buf = Vec::new();
    File::open(key).unwrap().read_to_end(&mut key_buf)?;
    let key_pem = pem::parse(&key_buf)?;

    let mut cert_buf = Vec::new();
    File::open(cert).unwrap().read_to_end(&mut cert_buf)?;
    let cert_pem = pem::parse(&cert_buf)?;

    let pfx = p12::PFX::new(&cert_pem.contents, &key_pem.contents, None, "", "")
        .expect("Failed to convert");

    let pkcs12der = pfx.to_der();

    let mut outf = File::create(out)?;
    outf.write_all(&pkcs12der)?;

    Ok(())
}

Trying to do openssl pkcs12 -info -in output.pfx on the created file gives:

Enter Import Password:
MAC: sha1, Iteration 2048
MAC length: 20, salt length: 8
PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 2048
Certificate bag
Bag Attributes
    friendlyName:
    localKeyID: [snip]

[correct cert data]

PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
Bag Attributes
    friendlyName:
    localKeyID: [snip]
Error outputting keys and certificates
140280276436352:error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag:crypto/asn1/tasn_dec.c:1149:
140280276436352:error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:309:Type=X509_ALGOR
140280276436352:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=pkeyalg, Type=PKCS8_PRIV_KEY_INFO
140280276436352:error:2306A065:PKCS12 routines:PKCS12_item_decrypt_d2i:decode error:crypto/pkcs12/p12_decr.c:114:

Any help would be much appreciated :)

nicklan commented 3 years ago

Ahh, the key_der arg has to be pkcs8 encoded (might be nice to specify that in the docs). for anyone looking to do something like this in the future, you can convert pkcs1 der bytes to pkcs8 like so:

// convert a pkcs1 der to pkcs8 format
fn pkcs1to8(pkcs1: &[u8]) -> Vec<u8> {
    let oid = ObjectIdentifier::from_slice(&[1, 2, 840, 113_549, 1, 1, 1]);
    yasna::construct_der(|writer| {
        writer.write_sequence(|writer| {
            writer.next().write_u32(0);
            writer.next().write_sequence(|writer| {
                writer.next().write_oid(&oid);
                writer.next().write_null();
            });
            writer.next().write_bytes(pkcs1);
        })
    })
}