libtomcrypt icon indicating copy to clipboard operation
libtomcrypt copied to clipboard

Add PEM support

Open sjaeckel opened this issue 2 years ago • 43 comments

Checklist

  • [x] documentation is added or updated
  • [x] tests are added or updated

Summary

This adds support to decode most variations of PEM files.

Changes to existing public APIs

The following public APIs have been changed. None of those APIs have been officially released.

  • ed25519_import_pkcs8()
  • ecc_import_pkcs8()
  • rsa_import_pkcs8()
  • x25519_import_pkcs8()

New public APIs and structs

structs

  • typedef struct password_ctx - a struct containing a call-back function that will be called once a password is required and the according opaque userdata pointer usually provided
  • typedef struct ltc_pka_key - a union containing all supported PK keys

PKCS#8 APIs

  • dh_import_pkcs8()
  • dsa_import_pkcs8()

PEM bytewise APIs

  • pem_decode()
  • pem_decode_pkcs()
  • pem_decode_openssh()

PEM FILE-based APIs

  • pem_decode_filehandle()
  • pem_decode_pkcs_filehandle()
  • pem_decode_openssh_filehandle()

New demos

  • openssh-privkey - not really a usable demo, more like a historical artifact of what this started from

Details

It brings support for:

  • OpenSSH style private key storage, both plain and encrypted, and public keys (in PEM format. authorized_keys format not supported yet)
  • PEM style private key storage, both plain and encrypted, and public keys
  • PKCS#8 style private key storage, both plain and encrypted

All supported PK crypto algorithms can be decoded:

  • Curve25519 (Ed25519 & X25519)
  • DH
  • DSA
  • ECC
  • RSA

sjaeckel avatar Mar 16 '22 20:03 sjaeckel

@karel-m do you maybe have time to review this? otherwise I'll merge it in the next days

sjaeckel avatar Jun 21 '23 11:06 sjaeckel

In my perl module test suite I have these (the password is: secret)

  • https://github.com/DCIT/perl-CryptX/blob/master/t/data/dsa-seed.pem
  • https://github.com/DCIT/perl-CryptX/blob/master/t/data/ec-seed.pem
  • https://github.com/DCIT/perl-CryptX/blob/master/t/data/rsa-seed.pem

Do we want to support them?

karel-m avatar Oct 09 '23 13:10 karel-m

I see these warnings

$ make CFLAGS="-O2 -DUSE_LTM -DLTM_DESC -I../libtommath -Wall" -f makefile.unix
cc -Isrc/headers -Itests -DLTC_SOURCE -O2 -DUSE_LTM -DLTM_DESC -I../libtommath -Wall -c src/pk/ecc/ecc_import_openssl.c -o src/pk/ecc/ecc_import_openssl.o
src/pk/ecc/ecc_import_openssl.c: In function ‘s_ecc_import_private_with_oid’:
src/pk/ecc/ecc_import_openssl.c:30:10: warning: implicit declaration of function ‘ecc_import_with_oid’ [-Wimplicit-function-declaration]
   30 |    err = ecc_import_with_oid(bin_k, seq_priv[1].size, curveoid, custom[0].size, PK_PRIVATE, key);
      |          ^~~~~~~~~~~~~~~~~~~
src/pk/ecc/ecc_import_openssl.c:14:25: warning: unused variable ‘curve’ [-Wunused-variable]
   14 |    const ltc_ecc_curve *curve;
      |                         ^~~~~
src/pk/ecc/ecc_import_openssl.c:13:9: warning: unused variable ‘OID’ [-Wunused-variable]
   13 |    char OID[256];
      |         ^~~
src/pk/ecc/ecc_import_openssl.c:12:18: warning: unused variable ‘len’ [-Wunused-variable]
   12 |    unsigned long len, pkver = 0, curveoid[16];
      |                  ^~~
cc -Isrc/headers -Itests -DLTC_SOURCE -O2 -DUSE_LTM -DLTM_DESC -I../libtommath -Wall -c src/pk/ecc/ecc_import_x509.c -o src/pk/ecc/ecc_import_x509.o
src/pk/ecc/ecc_import_x509.c: In function ‘s_ecc_import_x509_with_oid’:
src/pk/ecc/ecc_import_x509.c:21:10: warning: implicit declaration of function ‘ecc_import_with_oid’; did you mean ‘s_ecc_import_x509_with_oid’? [-Wimplicit-function-declaration]
   21 |    err = ecc_import_with_oid(bin_xy, len_xy, curveoid, len_oid, PK_PUBLIC, key);
      |          ^~~~~~~~~~~~~~~~~~~
      |          s_ecc_import_x509_with_oid
src/pk/ecc/ecc_import_x509.c:13:25: warning: unused variable ‘curve’ [-Wunused-variable]
   13 |    const ltc_ecc_curve *curve;
      |                         ^~~~~
src/pk/ecc/ecc_import_x509.c:12:9: warning: unused variable ‘OID’ [-Wunused-variable]
   12 |    char OID[256];
      |         ^~~
src/pk/ecc/ecc_import_x509.c:11:35: warning: unused variable ‘len’ [-Wunused-variable]
   11 |    unsigned long len_xy, len_oid, len;
      |                                   ^~~
src/pk/ecc/ecc_import_x509.c: In function ‘ecc_import_subject_public_key_info’:
src/pk/ecc/ecc_import_x509.c:34:10: warning: implicit declaration of function ‘ecc_import_with_curve’ [-Wimplicit-function-declaration]
   34 |    err = ecc_import_with_curve(in, inlen, PK_PUBLIC, key);
      |          ^~~~~~~~~~~~~~~~~~~~~

karel-m avatar Oct 09 '23 13:10 karel-m

Yeah, something is lost somewhere ... currently looking into it.

sjaeckel avatar Oct 09 '23 14:10 sjaeckel

If we want to support even more ciphers here is how you can generate more test vectors via openssl

openssl genpkey -algorithm rsa -out rsa_priv.pem

openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-128-cbc       -out rsa_priv-aes-128-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-128-cfb       -out rsa_priv-aes-128-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-128-cfb1      -out rsa_priv-aes-128-cfb1.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-128-cfb8      -out rsa_priv-aes-128-cfb8.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-128-ctr       -out rsa_priv-aes-128-ctr.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-128-ofb       -out rsa_priv-aes-128-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-192-cbc       -out rsa_priv-aes-192-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-192-cfb       -out rsa_priv-aes-192-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-192-cfb1      -out rsa_priv-aes-192-cfb1.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-192-cfb8      -out rsa_priv-aes-192-cfb8.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-192-ctr       -out rsa_priv-aes-192-ctr.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-192-ofb       -out rsa_priv-aes-192-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-256-cbc       -out rsa_priv-aes-256-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-256-cfb       -out rsa_priv-aes-256-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-256-cfb1      -out rsa_priv-aes-256-cfb1.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-256-cfb8      -out rsa_priv-aes-256-cfb8.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-256-ctr       -out rsa_priv-aes-256-ctr.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aes-256-ofb       -out rsa_priv-aes-256-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-128-cbc      -out rsa_priv-aria-128-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-128-cfb      -out rsa_priv-aria-128-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-128-cfb1     -out rsa_priv-aria-128-cfb1.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-128-cfb8     -out rsa_priv-aria-128-cfb8.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-128-ctr      -out rsa_priv-aria-128-ctr.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-128-ofb      -out rsa_priv-aria-128-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-192-cbc      -out rsa_priv-aria-192-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-192-cfb      -out rsa_priv-aria-192-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-192-cfb1     -out rsa_priv-aria-192-cfb1.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-192-cfb8     -out rsa_priv-aria-192-cfb8.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-192-ctr      -out rsa_priv-aria-192-ctr.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-192-ofb      -out rsa_priv-aria-192-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-256-cbc      -out rsa_priv-aria-256-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-256-cfb      -out rsa_priv-aria-256-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-256-cfb1     -out rsa_priv-aria-256-cfb1.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-256-cfb8     -out rsa_priv-aria-256-cfb8.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-256-ctr      -out rsa_priv-aria-256-ctr.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -aria-256-ofb      -out rsa_priv-aria-256-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -bf-cbc            -out rsa_priv-bf-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -bf-cfb            -out rsa_priv-bf-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -bf-ofb            -out rsa_priv-bf-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-128-cbc  -out rsa_priv-camellia-128-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-128-cfb  -out rsa_priv-camellia-128-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-128-cfb1 -out rsa_priv-camellia-128-cfb1.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-128-cfb8 -out rsa_priv-camellia-128-cfb8.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-128-ctr  -out rsa_priv-camellia-128-ctr.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-128-ofb  -out rsa_priv-camellia-128-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-192-cbc  -out rsa_priv-camellia-192-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-192-cfb  -out rsa_priv-camellia-192-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-192-cfb1 -out rsa_priv-camellia-192-cfb1.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-192-cfb8 -out rsa_priv-camellia-192-cfb8.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-192-ctr  -out rsa_priv-camellia-192-ctr.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-192-ofb  -out rsa_priv-camellia-192-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-256-cbc  -out rsa_priv-camellia-256-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-256-cfb  -out rsa_priv-camellia-256-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-256-cfb1 -out rsa_priv-camellia-256-cfb1.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-256-cfb8 -out rsa_priv-camellia-256-cfb8.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-256-ctr  -out rsa_priv-camellia-256-ctr.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -camellia-256-ofb  -out rsa_priv-camellia-256-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -cast5-cbc         -out rsa_priv-cast5-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -cast5-cfb         -out rsa_priv-cast5-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -cast5-ofb         -out rsa_priv-cast5-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -chacha20          -out rsa_priv-chacha20.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-cbc           -out rsa_priv-des-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-cfb           -out rsa_priv-des-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-cfb1          -out rsa_priv-des-cfb1.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-cfb8          -out rsa_priv-des-cfb8.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-ede-cbc       -out rsa_priv-des-ede-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-ede-cfb       -out rsa_priv-des-ede-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-ede-ofb       -out rsa_priv-des-ede-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-ede3-cbc      -out rsa_priv-des-ede3-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-ede3-cfb      -out rsa_priv-des-ede3-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-ede3-cfb1     -out rsa_priv-des-ede3-cfb1.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-ede3-cfb8     -out rsa_priv-des-ede3-cfb8.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-ede3-ofb      -out rsa_priv-des-ede3-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -des-ofb           -out rsa_priv-des-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -desx-cbc          -out rsa_priv-desx-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -idea-cbc          -out rsa_priv-idea-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -idea-cfb          -out rsa_priv-idea-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -idea-ofb          -out rsa_priv-idea-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -rc2-40-cbc        -out rsa_priv-rc2-40-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -rc2-64-cbc        -out rsa_priv-rc2-64-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -rc2-cbc           -out rsa_priv-rc2-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -rc2-cfb           -out rsa_priv-rc2-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -rc2-ofb           -out rsa_priv-rc2-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -rc5-cbc           -out rsa_priv-rc5-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -rc5-cfb           -out rsa_priv-rc5-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -rc5-ofb           -out rsa_priv-rc5-ofb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -seed-cbc          -out rsa_priv-seed-cbc.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -seed-cfb          -out rsa_priv-seed-cfb.pem
openssl pkey -in rsa_priv.pem -inform PEM -traditional -outform PEM -passout pass:secret -seed-ofb          -out rsa_priv-seed-ofb.pem

karel-m avatar Oct 10 '23 10:10 karel-m

In my perl module test suite I have these (the password is: secret)

  • https://github.com/DCIT/perl-CryptX/blob/master/t/data/dsa-seed.pem
  • https://github.com/DCIT/perl-CryptX/blob/master/t/data/ec-seed.pem
  • https://github.com/DCIT/perl-CryptX/blob/master/t/data/rsa-seed.pem

Do we want to support them?

I've also added support for seed. I had to create our own keys, since the ones you have don't match the private keys we already use.

FYI seed is now a legacy algorithm in OpenSSL

sjaeckel avatar Oct 10 '23 10:10 sjaeckel

If we want to support even more ciphers here is how you can generate more test vectors via openssl

hmm, I'll have a look

sjaeckel avatar Oct 10 '23 10:10 sjaeckel

Everything builds fine; however, adopting the new concept of password_ctx into my perl module will take some time before I can approve that it is working for me.

karel-m avatar Oct 10 '23 10:10 karel-m

I built openssl with RC5 enabled, but pkey doesn't seem to recognize the different rc5 options and I'm too tired to debug what went wrong ... Do you have a working openssl with RC5 support? If yes, could you please create the rc5 files from tests/pem/rsa.pem and upload them here?

sjaeckel avatar Oct 10 '23 18:10 sjaeckel

Do you have a working openssl with RC5 support? If yes, could you please create the rc5 files from tests/pem/rsa.pem and upload them here?

Done

karel-m avatar Oct 12 '23 17:10 karel-m

Are we able to load public keys in PEM format like this?

-----BEGIN PUBLIC KEY-----
MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD/////////////////
///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb
/NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh
AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABMBot1SHekqz
KKVpusbUZKgbF+Un0tZSVyq7Eb2jVy1Qv4znY0WQ0pI6AxEspq7jTlPIcWtDRD4S
NAJGQ287jIo=
-----END PUBLIC KEY-----

karel-m avatar Oct 12 '23 19:10 karel-m

Would be nice if we can load this:

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA0KXMyuA9+cL1xMjAzoQNYs3ieZkNxnJxXvgDYx+vb+K30DiBdQyM5i7nCUcQ
oMPswnNTCx4NBJX4km0pp53NsqGIcT+OM0URPWMaCfVeAvYFPYe5BBxtVKQit0qOD95Mb13oxr3m
LKC1VKHsvbNSexlkjebq61lhirBlDGla6d1t9XElkLnZ+Z/H+BCPgGpKEriSQAcp27Ke6EbHlVNo
l25lnV6Z3pZkmeAv9SSWEnw/MHrG64AM7e0izOaNtPheLp1PGqp5vD2HgMD7L6VZn+PsZ4RPskd1
bVaxfsbdvgUD6C2hhrxle9QUtzhfi0MO1sq5+B4wJ6yT1jd3n9uujwIDAQABAoIBAAntXD0/hm4G
lXyg6UeKJzw5u9pO6sWz4UAEVd5BU4QOdJzJa3i/DvR5a9BYW2qtbRY4DXiccUB0GukV8jhBklgQ
RnZ48Hzw/tJ9uhnvh4262IymaKpQ6Job2x5UbkZEAef/PwQ3DydgGBs9lGQsOYhA24oYNWTa56ta
cYcHJju1PCMF23rNVx49hSbG/H3TNRAAqOjmYsnvoG+w62Si1np7IBdlIbSdnTYC27kqRIBTIhMW
xkdWSChsgIbrNA5iYtOOeJ4yq17oAikEpUiDwMYqd522WXVRHvleHJQ9CnneOiTuRvnWHTrjeeS+
lW1lPWQMTzdaTVLV0i+5+F5MIP0CgYEA0+8AKP+rUI4nc8ZZ5CioD7DpIRNGtD8/86QAv4w49nmX
P+g9TBmItLD7mQzjOGxrbe8Stt4hALUIb2Oe5beJQDlKJpe1Y6sSk9+Tx6IdgY75NWjvhQCnJu28
QQXbO8Q/Eapqz/VH18cXLYfZnScI2toJXC8GwghQM8NYTwdimmUCgYEA/AfkaxY8q2qDuORn0WlT
SyB33N7sro/PwMOtLrosSwLSNyNpmQxiqSPSLhBxnO0ZHiMcSDL7SJbs3C4fOWiNImx7RuNfk8vY
Ox9WowtmYOC+5D5xnJ9TPvuKBhjsLRZMwK5k8gr7iIwU6v+Mjoif8SJ6MRUrPiNDK0ChHGVBu+MC
gYBIbxQv7wofUyaaxD0u5NJj4oQbYNo2erOh0vjKfuNtIiuWlQp2OvflQeQL8EKsoymofiB4Tb0b
38PNRlAllTAcujfkrs85DFwiHDUG8xqAkFwObBoI7Cs0++Xul1DRwYYIxKUTBHMUhaAfWKIAuzmk
iwbN8eiuYmb++hHxmMWTnQKBgEWXKEspaLcsQhLbfo8kNguYe4BRTaklrIfdgARXA8Pyk3kGHjJU
aSmq6m4tvDFIhpb7uuN0sE3q3pwtYBHJ/K50pdV9EvcMYjhw/ssmaq51YEBFvbkxhRru+b2VRCFu
9uJ9RQJQZgPeKih5R6ZTs1Yx3uuOnNIbioB26AWfL/dhAoGACIxtQG+DPfc8i3NFSOA4UmGtUfQY
fP4V9/26RAZ0o5PM9arVxp6gIZzU5++83DFCmlPjvN7cbSQmQgkjn7I5KJkiUEB0i95hDRISgaNl
QsvXdLhE3x77KR/76AAxv+4VxK6y4rrbi1MQwRCEVjp6BVzvdyT+2lMexhLmzucpP3w=
-----END RSA PRIVATE KEY-----

karel-m avatar Oct 12 '23 22:10 karel-m

Would be nice if we can load this:

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA0KXMyuA9+cL1xMjAzoQNYs3ieZkNxnJxXvgDYx+vb+K30DiBdQyM5i7nCUcQ
oMPswnNTCx4NBJX4km0pp53NsqGIcT+OM0URPWMaCfVeAvYFPYe5BBxtVKQit0qOD95Mb13oxr3m
LKC1VKHsvbNSexlkjebq61lhirBlDGla6d1t9XElkLnZ+Z/H+BCPgGpKEriSQAcp27Ke6EbHlVNo
l25lnV6Z3pZkmeAv9SSWEnw/MHrG64AM7e0izOaNtPheLp1PGqp5vD2HgMD7L6VZn+PsZ4RPskd1
bVaxfsbdvgUD6C2hhrxle9QUtzhfi0MO1sq5+B4wJ6yT1jd3n9uujwIDAQABAoIBAAntXD0/hm4G
lXyg6UeKJzw5u9pO6sWz4UAEVd5BU4QOdJzJa3i/DvR5a9BYW2qtbRY4DXiccUB0GukV8jhBklgQ
RnZ48Hzw/tJ9uhnvh4262IymaKpQ6Job2x5UbkZEAef/PwQ3DydgGBs9lGQsOYhA24oYNWTa56ta
cYcHJju1PCMF23rNVx49hSbG/H3TNRAAqOjmYsnvoG+w62Si1np7IBdlIbSdnTYC27kqRIBTIhMW
xkdWSChsgIbrNA5iYtOOeJ4yq17oAikEpUiDwMYqd522WXVRHvleHJQ9CnneOiTuRvnWHTrjeeS+
lW1lPWQMTzdaTVLV0i+5+F5MIP0CgYEA0+8AKP+rUI4nc8ZZ5CioD7DpIRNGtD8/86QAv4w49nmX
P+g9TBmItLD7mQzjOGxrbe8Stt4hALUIb2Oe5beJQDlKJpe1Y6sSk9+Tx6IdgY75NWjvhQCnJu28
QQXbO8Q/Eapqz/VH18cXLYfZnScI2toJXC8GwghQM8NYTwdimmUCgYEA/AfkaxY8q2qDuORn0WlT
SyB33N7sro/PwMOtLrosSwLSNyNpmQxiqSPSLhBxnO0ZHiMcSDL7SJbs3C4fOWiNImx7RuNfk8vY
Ox9WowtmYOC+5D5xnJ9TPvuKBhjsLRZMwK5k8gr7iIwU6v+Mjoif8SJ6MRUrPiNDK0ChHGVBu+MC
gYBIbxQv7wofUyaaxD0u5NJj4oQbYNo2erOh0vjKfuNtIiuWlQp2OvflQeQL8EKsoymofiB4Tb0b
38PNRlAllTAcujfkrs85DFwiHDUG8xqAkFwObBoI7Cs0++Xul1DRwYYIxKUTBHMUhaAfWKIAuzmk
iwbN8eiuYmb++hHxmMWTnQKBgEWXKEspaLcsQhLbfo8kNguYe4BRTaklrIfdgARXA8Pyk3kGHjJU
aSmq6m4tvDFIhpb7uuN0sE3q3pwtYBHJ/K50pdV9EvcMYjhw/ssmaq51YEBFvbkxhRru+b2VRCFu
9uJ9RQJQZgPeKih5R6ZTs1Yx3uuOnNIbioB26AWfL/dhAoGACIxtQG+DPfc8i3NFSOA4UmGtUfQY
fP4V9/26RAZ0o5PM9arVxp6gIZzU5++83DFCmlPjvN7cbSQmQgkjn7I5KJkiUEB0i95hDRISgaNl
QsvXdLhE3x77KR/76AAxv+4VxK6y4rrbi1MQwRCEVjp6BVzvdyT+2lMexhLmzucpP3w=
-----END RSA PRIVATE KEY-----

Where does this evil file originate? :D 77 chars line width ... that's very naughty and a lot more than the expected 72 chars ...

I'm gonna increase the max line length to 80.

sjaeckel avatar Oct 13 '23 10:10 sjaeckel

I am unable to load this X25519 public key

-----BEGIN PUBLIC KEY-----
MCowBQYDK2VuAyEA6ngG9yGoVwUSyPbvtOjWIMSaUp5N9eqnfexkb7HofkE=
-----END PUBLIC KEY-----

karel-m avatar Oct 14 '23 09:10 karel-m

I am unable to load this X25519 public key

-----BEGIN PUBLIC KEY-----
MCowBQYDK2VuAyEA6ngG9yGoVwUSyPbvtOjWIMSaUp5N9eqnfexkb7HofkE=
-----END PUBLIC KEY-----

I indeed forgot x25519 ... added now!

sjaeckel avatar Oct 14 '23 09:10 sjaeckel

... and I've added a testvector for a DSA public key.

sjaeckel avatar Oct 14 '23 09:10 sjaeckel

Another crazy/evil format I have in my perl module test suite (no idea where it comes from, but providing the fact that it is tested in sshkey.t it might be generated by something like ssh-keygen)

-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALjnyTSKAWBy+SsONQqjSAiA9bT7tAQ9yTv8NcikYCQfMcNNAu7v8jPE
EMIvuJCEXZ5DBpH+z1JeOzYNX85PdJczdCMk7g9LeceTN8/tmOqb0sZKJwGBHzHk
s+bGg1UDeo4icw/nGGGBsphi6y4EwCWkSCr9P24K8si69GcaEFMPAgMBAAE=
-----END RSA PUBLIC KEY-----

karel-m avatar Oct 14 '23 11:10 karel-m

I am not sure whether this is not too much for pem_decode_pkcs but what about loading public keys from:

-----BEGIN CERTIFICATE-----
MIIBODCB66ADAgECAhRWDU9FZBBUZ7KTdX8f7Bco8jsoaTAFBgMrZXAwETEPMA0G
A1UEAwwGQ3J5cHRYMCAXDTIwMDExOTEzMDIwMloYDzIyOTMxMTAyMTMwMjAyWjAR
MQ8wDQYDVQQDDAZDcnlwdFgwKjAFBgMrZXADIQCgXRrqWDCsmmXN+zhGYNSX42l8
RrQZzyzshd6L0kVFnaNTMFEwHQYDVR0OBBYEFHCGFtVibAxxWYyRt5wazMpqSZDV
MB8GA1UdIwQYMBaAFHCGFtVibAxxWYyRt5wazMpqSZDVMA8GA1UdEwEB/wQFMAMB
Af8wBQYDK2VwA0EAqG/+98smzqF/wmFX3zHXSaA67as202HnBJod1Tiurw1f+lr3
BX6OMtsDpgRq9O77IF1Qyx/MdJEwwErczOIbAA==
-----END CERTIFICATE-----

karel-m avatar Oct 14 '23 11:10 karel-m

I am trying to use pem_decode_openssh to load this key:

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACC9F7IhXEQ6eh6bKGpPDnYogTCYTNlCrMzU8aBku3SfvgAAAJBdUBO/XVAT
vwAAAAtzc2gtZWQyNTUxOQAAACC9F7IhXEQ6eh6bKGpPDnYogTCYTNlCrMzU8aBku3Sfvg
AAAEDVvPqQHjnRzlV/e2kq+R5egY12xCIw9mJIuVWBm05ZBL0XsiFcRDp6Hpsoak8OdiiB
MJhM2UKszNTxoGS7dJ++AAAABkNyeXB0WAECAwQFBgc=
-----END OPENSSH PRIVATE KEY-----

But it seems that both pub/priv buffers: loaded_key.u.ed25519.pub / loaded_key.u.ed25519.priv contain the same data

BD17B2215C443A7A1E9B286A4F0E76288130984CD942ACCCD4F1A064BB749FBE

which is the expected public key value, the expected private key value is:

D5BCFA901E39D1CE557F7B692AF91E5E818D76C42230F66248B955819B4E5904

I think there is a bug in ssh_decode_ed25519

-  if ((err = ed25519_import_raw(&privkey[32], 32, PK_PRIVATE, &key->u.ed25519)) != CRYPT_OK) {
+  if ((err = ed25519_import_raw(privkey, 32, PK_PRIVATE, &key->u.ed25519)) != CRYPT_OK) {

karel-m avatar Oct 14 '23 12:10 karel-m

And what about this format?

---- BEGIN SSH2 PUBLIC KEY ----
Comment: "1536-bit RSA, converted by miko@HIROKO from OpenSSH"
AAAAB3NzaC1yc2EAAAADAQABAAAAwQCkYHef/kFhdtEwG4YZfanYY92cmDX9gqw7OE2dxM
yQyj5Eyn/ztaIIERJGv2BG7TlEi8Gd83wFvSrqk4diHycQm2FbLtp258buy/PYCY3cvxYL
1imUxt6aPeLphzxQpt2dSwCom6M5Dq/sxB4YV+lvVpWZEuIFzsfGtqiLO7U4x80lXC1430
MtN5Z6nYTOVtktYkFJCmMSThYice6L4RHdTNejQZlmKGfLEKeR3wTwBIfLO9XFkSlHz2Uk
4q/Clr0=
---- END SSH2 PUBLIC KEY ----

It is basically the same (nearly) as:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAwQCkYHef/kFhdtEwG4YZfanYY92cmDX9gqw7OE2dxMyQyj5Eyn/ztaIIERJGv2BG7TlEi8Gd83wFvSrqk4diHycQm2FbLtp258buy/PYCY3cvxYL1imUxt6aPeLphzxQpt2dSwCom6M5Dq/sxB4YV+lvVpWZEuIFzsfGtqiLO7U4x80lXC1430MtN5Z6nYTOVtktYkFJCmMSThYice6L4RHdTNejQZlmKGfLEKeR3wTwBIfLO9XFkSlHz2Uk4q/Clr0= comment for rsa/1536 key

karel-m avatar Oct 14 '23 17:10 karel-m

I am trying to use pem_decode_openssh to load:

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAIEAuOfJNIoBYHL5Kw41CqNICID1tPu0BD3JO/w1yKRgJB8xw00C7u/y
M8QQwi+4kIRdnkMGkf7PUl47Ng1fzk90lzN0IyTuD0t5x5M3z+2Y6pvSxkonAYEfMeSz5s
aDVQN6jiJzD+cYYYGymGLrLgTAJaRIKv0/bgryyLr0ZxoQUw8AAAII7z6CTO8+gkwAAAAH
c3NoLXJzYQAAAIEAuOfJNIoBYHL5Kw41CqNICID1tPu0BD3JO/w1yKRgJB8xw00C7u/yM8
QQwi+4kIRdnkMGkf7PUl47Ng1fzk90lzN0IyTuD0t5x5M3z+2Y6pvSxkonAYEfMeSz5saD
VQN6jiJzD+cYYYGymGLrLgTAJaRIKv0/bgryyLr0ZxoQUw8AAAADAQABAAAAgA+VIQS3eK
Q7LDpvqRKrbf+hdpN4/tO4rUPL3nB5QczpgBUYYV3nhL7OECd9RA2Ryh3zQhN9qNUlMdI9
UEyfr5CFh3EJi0fPXC0TpQeHMm/nuJIuPN0Tq+p4gzYZ4inmnlvUBjBByAG3/FG4LgNr1O
KfvcHHpjYhVCXMIkO+NMzRAAAAQAxffrTSdcbVtc/8Ev7tSBk5DC2AKcqlDH9nsH+crw/M
sR+DxHmBAvevpJ+m3RBK5OrLDj9jtZ/Y8CJUcmYHCjoAAABBAPYbLJBvMRRuKLAaMZsfXf
VpW87YW1ilhZyRCGB+sF3CQsQJQNEviCCoak6COcXhYVdrZQL8G8vJIASN/AGFTLcAAABB
AMBWwig0FiG5a0KAnhR1O+XwEmwl8BBrTCDv/hk/YXKVAAeYkI8DngDEBG7O2ns0rnxmyM
lFC+gCQRqERkVXBGkAAAATVGhpcyBpcyBhIHRlc3Qga2V5IQ==
-----END OPENSSH PRIVATE KEY-----

And pem_decode_pkcs to load the same key:

-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALjnyTSKAWBy+SsO
NQqjSAiA9bT7tAQ9yTv8NcikYCQfMcNNAu7v8jPEEMIvuJCEXZ5DBpH+z1JeOzYN
X85PdJczdCMk7g9LeceTN8/tmOqb0sZKJwGBHzHks+bGg1UDeo4icw/nGGGBsphi
6y4EwCWkSCr9P24K8si69GcaEFMPAgMBAAECgYAPlSEEt3ikOyw6b6kSq23/oXaT
eP7TuK1Dy95weUHM6YAVGGFd54S+zhAnfUQNkcod80ITfajVJTHSPVBMn6+QhYdx
CYtHz1wtE6UHhzJv57iSLjzdE6vqeIM2GeIp5p5b1AYwQcgBt/xRuC4Da9Tin73B
x6Y2IVQlzCJDvjTM0QJBAPYbLJBvMRRuKLAaMZsfXfVpW87YW1ilhZyRCGB+sF3C
QsQJQNEviCCoak6COcXhYVdrZQL8G8vJIASN/AGFTLcCQQDAVsIoNBYhuWtCgJ4U
dTvl8BJsJfAQa0wg7/4ZP2FylQAHmJCPA54AxARuztp7NK58ZsjJRQvoAkEahEZF
VwRpAkAvAQ+o4mPIWCXTRJ122C3U4nOTdQU1UB/NwHGOJIRA1Ap2cKH9kgt42VG8
fujT33D9Blj7kfUpHdfMpuWb0L7PAkBq8pLpOfUocWqDwvKjW4Cf3XrQ6dNvvcnJ
8shuj4CG7vTiRGH1M8SylkwEtT5lDakMATcaOytgqYg7z1sniTgpAkAMX3600nXG
1bXP/BL+7UgZOQwtgCnKpQx/Z7B/nK8PzLEfg8R5gQL3r6Sfpt0QSuTqyw4/Y7Wf
2PAiVHJmBwo6
-----END PRIVATE KEY-----

pem_decode_openssh gives me RSA key with these internals:

{
  'N' => 'B8E7C9348A016072F92B0E350AA3480880F5B4FBB4043DC93BFC35C8A460241F31C34D02EEEFF233C410C22FB890845D9E430691FECF525E3B360D5FCE4F749733742324EE0F4B79C79337CFED98EA9BD2C64A2701811F31E4B3E6C68355037A8E22730FE7186181B29862EB2E04C025A4482AFD3F6E0AF2C8BAF4671A10530F',
  'd' => '0F952104B778A43B2C3A6FA912AB6DFFA1769378FED3B8AD43CBDE707941CCE9801518615DE784BECE10277D440D91CA1DF342137DA8D52531D23D504C9FAF90858771098B47CF5C2D13A50787326FE7B8922E3CDD13ABEA78833619E229E69E5BD4063041C801B7FC51B82E036BD4E29FBDC1C7A636215425CC2243BE34CCD1',
  'dP' => '6AF292E939F528716A83C2F2A35B809FDD7AD0E9D36FBDC9C9F2C86E8F8086EEF4E24461F533C4B2964C04B53E650DA90C01371A3B2B60A9883BCF5B27893829',
  'dQ' => '2F010FA8E263C85825D3449D76D82DD4E27393750535501FCDC0718E248440D40A7670A1FD920B78D951BC7EE8D3DF70FD0658FB91F5291DD7CCA6E59BD0BECF',
  'e' => '010001',
  'p' => 'C056C228341621B96B42809E14753BE5F0126C25F0106B4C20EFFE193F617295000798908F039E00C4046ECEDA7B34AE7C66C8C9450BE802411A844645570469',
  'q' => 'F61B2C906F31146E28B01A319B1F5DF5695BCED85B58A5859C9108607EB05DC242C40940D12F8820A86A4E8239C5E161576B6502FC1BCBC920048DFC01854CB7',
  'qP' => '0C5F7EB4D275C6D5B5CFFC12FEED4819390C2D8029CAA50C7F67B07F9CAF0FCCB11F83C4798102F7AFA49FA6DD104AE4EACB0E3F63B59FD8F022547266070A3A',
}

pem_decode_pkcs gives:

{
  'N' => 'B8E7C9348A016072F92B0E350AA3480880F5B4FBB4043DC93BFC35C8A460241F31C34D02EEEFF233C410C22FB890845D9E430691FECF525E3B360D5FCE4F749733742324EE0F4B79C79337CFED98EA9BD2C64A2701811F31E4B3E6C68355037A8E22730FE7186181B29862EB2E04C025A4482AFD3F6E0AF2C8BAF4671A10530F',
  'd' => '0F952104B778A43B2C3A6FA912AB6DFFA1769378FED3B8AD43CBDE707941CCE9801518615DE784BECE10277D440D91CA1DF342137DA8D52531D23D504C9FAF90858771098B47CF5C2D13A50787326FE7B8922E3CDD13ABEA78833619E229E69E5BD4063041C801B7FC51B82E036BD4E29FBDC1C7A636215425CC2243BE34CCD1',
  'dP' => '2F010FA8E263C85825D3449D76D82DD4E27393750535501FCDC0718E248440D40A7670A1FD920B78D951BC7EE8D3DF70FD0658FB91F5291DD7CCA6E59BD0BECF',
  'dQ' => '6AF292E939F528716A83C2F2A35B809FDD7AD0E9D36FBDC9C9F2C86E8F8086EEF4E24461F533C4B2964C04B53E650DA90C01371A3B2B60A9883BCF5B27893829',
  'e' => '010001',
  'p' => 'F61B2C906F31146E28B01A319B1F5DF5695BCED85B58A5859C9108607EB05DC242C40940D12F8820A86A4E8239C5E161576B6502FC1BCBC920048DFC01854CB7',
  'q' => 'C056C228341621B96B42809E14753BE5F0126C25F0106B4C20EFFE193F617295000798908F039E00C4046ECEDA7B34AE7C66C8C9450BE802411A844645570469',
  'qP' => '0C5F7EB4D275C6D5B5CFFC12FEED4819390C2D8029CAA50C7F67B07F9CAF0FCCB11F83C4798102F7AFA49FA6DD104AE4EACB0E3F63B59FD8F022547266070A3A',
}

Please note the swap of p/q + dP/dQ.

It is so strange that there still might be "something" on my side.

karel-m avatar Oct 15 '23 14:10 karel-m

Isn't ssh_decode_rsa missing:

key->u.rsa.type = PK_PRIVATE;

?

karel-m avatar Oct 15 '23 15:10 karel-m

Do we want to support loading DSA keys in openssh format?

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsQAAAAdzc2gtZH
NzAAAAgQClPP2r5pBXhp0qsGBu3WZ0JRvtNUDWsbtxeb9DXC/0kVFuyHaVKvLdeLIitJgO
so6YS4Tn+bfILoExFQZZT/OgDUmxYoB+1jd7+snSVqputKTYTRzf/+dHJzbSLF28Xqt1bb
COuKZB9TianmQxy5ru95OE9BCjs7MpUnxf8LVQSQAAABUAoabmyx1YsDwfo0r1G/HuEx0u
zwUAAACACQ9TzAokwkGtccg/zQljmowrn0ziMygIZupfp5QVT4iiPtutl6WLdduynuJjy/
FyQYs6E40kDdPLhzIP/C+lv3HTtmmfpoZAZ0tcQJvNwwMKi6w62kdcP+EERca+VW8svKp3
o6z40yaGwTdQRrL/OMB5I5qAp+qRSH5BmHgE5SYAAACAB2D1NczFQUw1q7u0jQuBtlMlhl
mGC4y8rQVR30JgWudQpqq0rNpAnxixgNcp32BDbMXCavZ7F62+Itex+QRyRZB9IOwVA6Xg
Xi6/ILCt1oH6lsLWbA5JbTm8PXIVA/7Iiuqv3ZP30iAdh6NIp3r+5OvGeWZDSOFzsLhLLA
FYZsAAAAHwKUeNkClHjZAAAAAHc3NoLWRzcwAAAIEApTz9q+aQV4adKrBgbt1mdCUb7TVA
1rG7cXm/Q1wv9JFRbsh2lSry3XiyIrSYDrKOmEuE5/m3yC6BMRUGWU/zoA1JsWKAftY3e/
rJ0laqbrSk2E0c3//nRyc20ixdvF6rdW2wjrimQfU4mp5kMcua7veThPQQo7OzKVJ8X/C1
UEkAAAAVAKGm5ssdWLA8H6NK9Rvx7hMdLs8FAAAAgAkPU8wKJMJBrXHIP80JY5qMK59M4j
MoCGbqX6eUFU+Ioj7brZeli3Xbsp7iY8vxckGLOhONJA3Ty4cyD/wvpb9x07Zpn6aGQGdL
XECbzcMDCousOtpHXD/hBEXGvlVvLLyqd6Os+NMmhsE3UEay/zjAeSOagKfqkUh+QZh4BO
UmAAAAgAdg9TXMxUFMNau7tI0LgbZTJYZZhguMvK0FUd9CYFrnUKaqtKzaQJ8YsYDXKd9g
Q2zFwmr2exetviLXsfkEckWQfSDsFQOl4F4uvyCwrdaB+pbC1mwOSW05vD1yFQP+yIrqr9
2T99IgHYejSKd6/uTrxnlmQ0jhc7C4SywBWGbAAAAAFQCYwb2dlv1ktqrIWBTO+Hn+CJ4w
RAAAABNUaGlzIGlzIGEgdGVzdCBrZXkhAQIDBAUGBw==
-----END OPENSSH PRIVATE KEY-----

karel-m avatar Oct 15 '23 15:10 karel-m

I am trying to use pem_decode_openssh to load:

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAIEAuOfJNIoBYHL5Kw41CqNICID1tPu0BD3JO/w1yKRgJB8xw00C7u/y
M8QQwi+4kIRdnkMGkf7PUl47Ng1fzk90lzN0IyTuD0t5x5M3z+2Y6pvSxkonAYEfMeSz5s
aDVQN6jiJzD+cYYYGymGLrLgTAJaRIKv0/bgryyLr0ZxoQUw8AAAII7z6CTO8+gkwAAAAH
c3NoLXJzYQAAAIEAuOfJNIoBYHL5Kw41CqNICID1tPu0BD3JO/w1yKRgJB8xw00C7u/yM8
QQwi+4kIRdnkMGkf7PUl47Ng1fzk90lzN0IyTuD0t5x5M3z+2Y6pvSxkonAYEfMeSz5saD
VQN6jiJzD+cYYYGymGLrLgTAJaRIKv0/bgryyLr0ZxoQUw8AAAADAQABAAAAgA+VIQS3eK
Q7LDpvqRKrbf+hdpN4/tO4rUPL3nB5QczpgBUYYV3nhL7OECd9RA2Ryh3zQhN9qNUlMdI9
UEyfr5CFh3EJi0fPXC0TpQeHMm/nuJIuPN0Tq+p4gzYZ4inmnlvUBjBByAG3/FG4LgNr1O
KfvcHHpjYhVCXMIkO+NMzRAAAAQAxffrTSdcbVtc/8Ev7tSBk5DC2AKcqlDH9nsH+crw/M
sR+DxHmBAvevpJ+m3RBK5OrLDj9jtZ/Y8CJUcmYHCjoAAABBAPYbLJBvMRRuKLAaMZsfXf
VpW87YW1ilhZyRCGB+sF3CQsQJQNEviCCoak6COcXhYVdrZQL8G8vJIASN/AGFTLcAAABB
AMBWwig0FiG5a0KAnhR1O+XwEmwl8BBrTCDv/hk/YXKVAAeYkI8DngDEBG7O2ns0rnxmyM
lFC+gCQRqERkVXBGkAAAATVGhpcyBpcyBhIHRlc3Qga2V5IQ==
-----END OPENSSH PRIVATE KEY-----

And pem_decode_pkcs to load the same key:

-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALjnyTSKAWBy+SsO
NQqjSAiA9bT7tAQ9yTv8NcikYCQfMcNNAu7v8jPEEMIvuJCEXZ5DBpH+z1JeOzYN
X85PdJczdCMk7g9LeceTN8/tmOqb0sZKJwGBHzHks+bGg1UDeo4icw/nGGGBsphi
6y4EwCWkSCr9P24K8si69GcaEFMPAgMBAAECgYAPlSEEt3ikOyw6b6kSq23/oXaT
eP7TuK1Dy95weUHM6YAVGGFd54S+zhAnfUQNkcod80ITfajVJTHSPVBMn6+QhYdx
CYtHz1wtE6UHhzJv57iSLjzdE6vqeIM2GeIp5p5b1AYwQcgBt/xRuC4Da9Tin73B
x6Y2IVQlzCJDvjTM0QJBAPYbLJBvMRRuKLAaMZsfXfVpW87YW1ilhZyRCGB+sF3C
QsQJQNEviCCoak6COcXhYVdrZQL8G8vJIASN/AGFTLcCQQDAVsIoNBYhuWtCgJ4U
dTvl8BJsJfAQa0wg7/4ZP2FylQAHmJCPA54AxARuztp7NK58ZsjJRQvoAkEahEZF
VwRpAkAvAQ+o4mPIWCXTRJ122C3U4nOTdQU1UB/NwHGOJIRA1Ap2cKH9kgt42VG8
fujT33D9Blj7kfUpHdfMpuWb0L7PAkBq8pLpOfUocWqDwvKjW4Cf3XrQ6dNvvcnJ
8shuj4CG7vTiRGH1M8SylkwEtT5lDakMATcaOytgqYg7z1sniTgpAkAMX3600nXG
1bXP/BL+7UgZOQwtgCnKpQx/Z7B/nK8PzLEfg8R5gQL3r6Sfpt0QSuTqyw4/Y7Wf
2PAiVHJmBwo6
-----END PRIVATE KEY-----

pem_decode_openssh gives me RSA key with these internals:

{
  'N' => 'B8E7C9348A016072F92B0E350AA3480880F5B4FBB4043DC93BFC35C8A460241F31C34D02EEEFF233C410C22FB890845D9E430691FECF525E3B360D5FCE4F749733742324EE0F4B79C79337CFED98EA9BD2C64A2701811F31E4B3E6C68355037A8E22730FE7186181B29862EB2E04C025A4482AFD3F6E0AF2C8BAF4671A10530F',
  'd' => '0F952104B778A43B2C3A6FA912AB6DFFA1769378FED3B8AD43CBDE707941CCE9801518615DE784BECE10277D440D91CA1DF342137DA8D52531D23D504C9FAF90858771098B47CF5C2D13A50787326FE7B8922E3CDD13ABEA78833619E229E69E5BD4063041C801B7FC51B82E036BD4E29FBDC1C7A636215425CC2243BE34CCD1',
  'dP' => '6AF292E939F528716A83C2F2A35B809FDD7AD0E9D36FBDC9C9F2C86E8F8086EEF4E24461F533C4B2964C04B53E650DA90C01371A3B2B60A9883BCF5B27893829',
  'dQ' => '2F010FA8E263C85825D3449D76D82DD4E27393750535501FCDC0718E248440D40A7670A1FD920B78D951BC7EE8D3DF70FD0658FB91F5291DD7CCA6E59BD0BECF',
  'e' => '010001',
  'p' => 'C056C228341621B96B42809E14753BE5F0126C25F0106B4C20EFFE193F617295000798908F039E00C4046ECEDA7B34AE7C66C8C9450BE802411A844645570469',
  'q' => 'F61B2C906F31146E28B01A319B1F5DF5695BCED85B58A5859C9108607EB05DC242C40940D12F8820A86A4E8239C5E161576B6502FC1BCBC920048DFC01854CB7',
  'qP' => '0C5F7EB4D275C6D5B5CFFC12FEED4819390C2D8029CAA50C7F67B07F9CAF0FCCB11F83C4798102F7AFA49FA6DD104AE4EACB0E3F63B59FD8F022547266070A3A',
}

pem_decode_pkcs gives:

{
  'N' => 'B8E7C9348A016072F92B0E350AA3480880F5B4FBB4043DC93BFC35C8A460241F31C34D02EEEFF233C410C22FB890845D9E430691FECF525E3B360D5FCE4F749733742324EE0F4B79C79337CFED98EA9BD2C64A2701811F31E4B3E6C68355037A8E22730FE7186181B29862EB2E04C025A4482AFD3F6E0AF2C8BAF4671A10530F',
  'd' => '0F952104B778A43B2C3A6FA912AB6DFFA1769378FED3B8AD43CBDE707941CCE9801518615DE784BECE10277D440D91CA1DF342137DA8D52531D23D504C9FAF90858771098B47CF5C2D13A50787326FE7B8922E3CDD13ABEA78833619E229E69E5BD4063041C801B7FC51B82E036BD4E29FBDC1C7A636215425CC2243BE34CCD1',
  'dP' => '2F010FA8E263C85825D3449D76D82DD4E27393750535501FCDC0718E248440D40A7670A1FD920B78D951BC7EE8D3DF70FD0658FB91F5291DD7CCA6E59BD0BECF',
  'dQ' => '6AF292E939F528716A83C2F2A35B809FDD7AD0E9D36FBDC9C9F2C86E8F8086EEF4E24461F533C4B2964C04B53E650DA90C01371A3B2B60A9883BCF5B27893829',
  'e' => '010001',
  'p' => 'F61B2C906F31146E28B01A319B1F5DF5695BCED85B58A5859C9108607EB05DC242C40940D12F8820A86A4E8239C5E161576B6502FC1BCBC920048DFC01854CB7',
  'q' => 'C056C228341621B96B42809E14753BE5F0126C25F0106B4C20EFFE193F617295000798908F039E00C4046ECEDA7B34AE7C66C8C9450BE802411A844645570469',
  'qP' => '0C5F7EB4D275C6D5B5CFFC12FEED4819390C2D8029CAA50C7F67B07F9CAF0FCCB11F83C4798102F7AFA49FA6DD104AE4EACB0E3F63B59FD8F022547266070A3A',
}

Please note the swap of p/q + dP/dQ.

It is so strange that there still might be "something" on my side.

Very possible that I got something wrong on the import side there! I'll have a look tomorrow, please keep posting your findings.

sjaeckel avatar Oct 15 '23 15:10 sjaeckel

my suggestion (UPDATED - now loads openssh-dsa keys)

diff --git a/src/ltc/misc/pem/pem.c b/src/ltc/misc/pem/pem.c
index fb1f412a..0b64a604 100644
--- a/src/ltc/misc/pem/pem.c
+++ b/src/ltc/misc/pem/pem.c
@@ -31,6 +31,12 @@ const struct pem_header_id pem_std_headers[] = {
      .has_more_headers = no,
      .flags = pf_public,
    },
+   {
+     SET_CSTR(.start, "-----BEGIN RSA PUBLIC KEY-----"),
+     SET_CSTR(.end, "-----END RSA PUBLIC KEY-----"),
+     .has_more_headers = maybe,
+     .pka = LTC_PKA_RSA,
+   },
    /* Regular plain or encrypted private keys */
    {
      SET_CSTR(.start, "-----BEGIN RSA PRIVATE KEY-----"),
diff --git a/src/ltc/misc/pem/pem_ssh.c b/src/ltc/misc/pem/pem_ssh.c
index 9347cf21..9c5d6deb 100644
--- a/src/ltc/misc/pem/pem_ssh.c
+++ b/src/ltc/misc/pem/pem_ssh.c
@@ -108,7 +108,7 @@ int ssh_decode_ed25519(const unsigned char *in, unsigned long *inlen, ltc_pka_ke
       goto cleanup;
    }

-   if ((err = ed25519_import_raw(&privkey[32], 32, PK_PRIVATE, &key->u.ed25519)) != CRYPT_OK) {
+   if ((err = ed25519_import_raw(privkey, 32, PK_PRIVATE, &key->u.ed25519)) != CRYPT_OK) {
       goto cleanup;
    }
    if (pubkeylen == sizeof(key->u.ed25519.pub)) {
@@ -131,7 +131,7 @@ int ssh_decode_rsa(const unsigned char *in, unsigned long *inlen, ltc_pka_key *k
    int err;
    void *tmp1, *tmp2;
    if ((err = mp_init_multi(&tmp1, &tmp2, NULL)) != CRYPT_OK) {
-      goto cleanup;
+      return err;
    }
    if ((err = rsa_init(&key->u.rsa)) != CRYPT_OK) {
       goto cleanup;
@@ -142,9 +142,10 @@ int ssh_decode_rsa(const unsigned char *in, unsigned long *inlen, ltc_pka_key *k
                                         LTC_SSHDATA_MPINT, key->u.rsa.e,
                                         LTC_SSHDATA_MPINT, key->u.rsa.d,
                                         LTC_SSHDATA_MPINT, key->u.rsa.qP,
-                                        LTC_SSHDATA_MPINT, key->u.rsa.q,
                                         LTC_SSHDATA_MPINT, key->u.rsa.p,
+                                        LTC_SSHDATA_MPINT, key->u.rsa.q,
                                         LTC_SSHDATA_EOL,    NULL)) != CRYPT_OK) {
+      rsa_free(&key->u.rsa);
       goto cleanup;
    }

@@ -154,6 +155,7 @@ int ssh_decode_rsa(const unsigned char *in, unsigned long *inlen, ltc_pka_key *k
    if ((err = mp_mod( key->u.rsa.d,  tmp2,  key->u.rsa.dQ)) != CRYPT_OK)         { goto cleanup; } /* dQ = d mod q-1 */

    key->id = LTC_PKA_RSA;
+   key->u.rsa.type = PK_PRIVATE;

 cleanup:
    mp_clear_multi(tmp2, tmp1, NULL);
@@ -162,6 +164,32 @@ cleanup:
 }
 #endif

+#ifdef LTC_MDSA
+int ssh_decode_dsa(const unsigned char *in, unsigned long *inlen, ltc_pka_key *key)
+{
+   int err;
+
+   if ((err = dsa_int_init(&key->u.dsa)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = ssh_decode_sequence_multi(in, inlen,
+                                        LTC_SSHDATA_MPINT, key->u.dsa.p,
+                                        LTC_SSHDATA_MPINT, key->u.dsa.q,
+                                        LTC_SSHDATA_MPINT, key->u.dsa.g,
+                                        LTC_SSHDATA_MPINT, key->u.dsa.y,
+                                        LTC_SSHDATA_MPINT, key->u.dsa.x,
+                                        LTC_SSHDATA_EOL,    NULL)) != CRYPT_OK) {
+      dsa_free(&key->u.dsa);
+      return err;
+   }
+
+   key->id = LTC_PKA_DSA;
+   key->u.dsa.qord = mp_unsigned_bin_size(key->u.dsa.q);
+   key->u.dsa.type = PK_PRIVATE;
+   return CRYPT_OK;
+}
+#endif
+
 struct ssh_pka {
    const char *name;
    int (*init)(const char*, ltc_pka_key*);
@@ -175,6 +203,9 @@ struct ssh_pka ssh_pkas[] = {
 #ifdef LTC_MRSA
                              { "ssh-rsa",     NULL,              ssh_decode_rsa },
 #endif
+#ifdef LTC_MDSA
+                             { "ssh-dss",     NULL,              ssh_decode_dsa },
+#endif
 #ifdef LTC_MECC
                              { NULL,          ssh_find_init_ecc, ssh_decode_ecdsa },
 #endif

karel-m avatar Oct 15 '23 15:10 karel-m

The full set of various keys created/converted by ssh-keygen are here https://github.com/DCIT/perl-CryptX/tree/master/t/data/ssh

Even with the patch from my previous post we are not able to load RFC4716 format:

---- BEGIN SSH2 PUBLIC KEY ----
Comment: "1024-bit RSA, converted by miko@YUE from OpenSSH"
AAAAB3NzaC1yc2EAAAADAQABAAAAgQC458k0igFgcvkrDjUKo0gIgPW0+7QEPck7/DXIpG
AkHzHDTQLu7/IzxBDCL7iQhF2eQwaR/s9SXjs2DV/OT3SXM3QjJO4PS3nHkzfP7Zjqm9LG
SicBgR8x5LPmxoNVA3qOInMP5xhhgbKYYusuBMAlpEgq/T9uCvLIuvRnGhBTDw==
---- END SSH2 PUBLIC KEY ----

and traditional public key:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC458k0igFgcvkrDjUKo0gIgPW0+7QEPck7/DXIpGAkHzHDTQLu7/IzxBDCL7iQhF2eQwaR/s9SXjs2DV/OT3SXM3QjJO4PS3nHkzfP7Zjqm9LGSicBgR8x5LPmxoNVA3qOInMP5xhhgbKYYusuBMAlpEgq/T9uCvLIuvRnGhBTDw== This is a test key!

On top of that it might be a good idea to be able to load public keys from PEM certificates like:

-----BEGIN CERTIFICATE-----
MIIBODCB66ADAgECAhRWDU9FZBBUZ7KTdX8f7Bco8jsoaTAFBgMrZXAwETEPMA0G
A1UEAwwGQ3J5cHRYMCAXDTIwMDExOTEzMDIwMloYDzIyOTMxMTAyMTMwMjAyWjAR
MQ8wDQYDVQQDDAZDcnlwdFgwKjAFBgMrZXADIQCgXRrqWDCsmmXN+zhGYNSX42l8
RrQZzyzshd6L0kVFnaNTMFEwHQYDVR0OBBYEFHCGFtVibAxxWYyRt5wazMpqSZDV
MB8GA1UdIwQYMBaAFHCGFtVibAxxWYyRt5wazMpqSZDVMA8GA1UdEwEB/wQFMAMB
Af8wBQYDK2VwA0EAqG/+98smzqF/wmFX3zHXSaA67as202HnBJod1Tiurw1f+lr3
BX6OMtsDpgRq9O77IF1Qyx/MdJEwwErczOIbAA==
-----END CERTIFICATE-----

All from me for today.

karel-m avatar Oct 15 '23 17:10 karel-m

A build with -Wall -Werror -Wextra fails like this https://github.com/DCIT/perl-CryptX/actions/runs/6525537050/job/17718404851

karel-m avatar Oct 15 '23 17:10 karel-m

A build with -Wall -Werror -Wextra fails like this https://github.com/DCIT/perl-CryptX/actions/runs/6525537050/job/17718404851

Not for me with any of those two versions of GCC:

$ cc --version
cc (Ubuntu 11.4.0-1ubuntu1~22.04) [...]
$ cc --version  
cc (GCC) 13.2.1 [...]

... also CI is running per default with those options enabled.

The full set of various keys created/converted by ssh-keygen are here https://github.com/DCIT/perl-CryptX/tree/master/t/data/ssh

Yeah, after having another look I guess it'd make sense to have:

int pem_decode_filehandle(FILE *f, ltc_pka_key *k, const password_ctx *pw_ctx);
int pem_decode(const void *buf, unsigned long len, ltc_pka_key *k, const password_ctx *pw_ctx);

Even with the patch from my previous post we are not able to load RFC4716 format: [...] On top of that it might be a good idea to be able to load public keys from PEM certificates like: [...] Do we want to support loading DSA keys in openssh format? [...]

Those should all be supported now.

and traditional public key:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC458k0igFgcvkrDjUKo0gIgPW0+7QEPck7/DXIpGAkHzHDTQLu7/IzxBDCL7iQhF2eQwaR/s9SXjs2DV/OT3SXM3QjJO4PS3nHkzfP7Zjqm9LGSicBgR8x5LPmxoNVA3qOInMP5xhhgbKYYusuBMAlpEgq/T9uCvLIuvRnGhBTDw== This is a test key!

This is still not supported and I didn't think it through yet ... This format is AFAIK usually only used in authorized_keys files and then it's most of the time multiple lines with multiple keys.

Maybe it'd make sense to provide a separate API int ssh_decode_public_key(const char *in, unsigned long inlen, ltc_pka_key *k);? ... and leave the reading of each line up to the user?

@mkj maybe you also have an opinion on that? :)

sjaeckel avatar Oct 16 '23 16:10 sjaeckel

int pem_decode_filehandle(FILE *f, ltc_pka_key *k, const password_ctx *pw_ctx);
int pem_decode(const void *buf, unsigned long len, ltc_pka_key *k, const password_ctx *pw_ctx);

I've added those, and the testfiles from https://github.com/DCIT/perl-CryptX/tree/master/t/data/ssh :)

... not sure whether CRYPT_UNKNOWN_PEM is a good error code ... proposals will be accepted!

sjaeckel avatar Oct 16 '23 17:10 sjaeckel

Would you mind adding also this:

diff --git a/src/ltc/misc/pem/pem.c b/src/ltc/misc/pem/pem.c
index e259a704..af5a34cc 100644
--- a/src/ltc/misc/pem/pem.c
+++ b/src/ltc/misc/pem/pem.c
@@ -38,6 +38,12 @@ const struct pem_header_id pem_std_headers[] = {
      .has_more_headers = no,
      .flags = pf_public,
    },
+   {
+     SET_CSTR(.start, "-----BEGIN RSA PUBLIC KEY-----"),
+     SET_CSTR(.end, "-----END RSA PUBLIC KEY-----"),
+     .has_more_headers = maybe,
+     .pka = LTC_PKA_RSA,
+   },
    /* Regular plain or encrypted private keys */
    {
      SET_CSTR(.start, "-----BEGIN RSA PRIVATE KEY-----"),

karel-m avatar Oct 16 '23 19:10 karel-m