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

Support EcDSA Keys with Named Curves #47

Draft
wants to merge 31 commits into
base: master
Choose a base branch
from

Conversation

rkeene
Copy link
Contributor

@rkeene rkeene commented Oct 17, 2022

This changeset adds support for EcDSA Keys with Named Curves. Additionally, it may make it easier to add other kinds of keys in the future.

Not done as part of this change:
Support GnuTLS

@alonbl
Copy link
Owner

alonbl commented Oct 17, 2022

Hi,

Great work!

First, please do not mark as fix #17 as I already explained to you that the problem there was the existence of EC certificate which caused the RSA certificates not to be accepted.

Please refactor/rename the entire keyutil module to keyinfo as it does nothing but that. As far as I understand the interface would be something like:

struct keyinfo_s;
typedef struct keyinfo_s *keyinfo;

struct key_data_list_s {
    struct key_data_list_s *next;
    char *type;
    char *value;
}

keyinfo keyinfo_new();
void keyinfo_free(keyinfo keyinfo);
int keyinfo_get_type(keyinfo keyinfo);
int keyinfo_from_der(keyinfo keyinfo, unsigned char *der, size_t len);
gcry_sexp_t *keyinfo_to_sexp(keyinfo keyinfo);
key_data_list *keyinfo_get_key_data(keyinfo keyinfo);
void key_data_free(key_data_list list);

What do you think? This way we focus in the key logic within the keyinfo module.
Notice that the type and I believe the curve should be acquired from the certificate.

Thank you for your help!
Alon

@rkeene
Copy link
Contributor Author

rkeene commented Oct 17, 2022

I'm not sure I understand the key_data_list_s linked-list. A given der (certificate)'s resultant keyinfo would only ever hold 1 key, is the list used for some other purpose ? What would value and type be ?

@alonbl
Copy link
Owner

alonbl commented Oct 17, 2022

I'm not sure I understand the key_data_list_s linked-list. A given der (certificate)'s resultant keyinfo would only ever hold 1 key, is the list used for some other purpose ? What would value and type be ?

all that needed in order to provide the key to assuan socket without the code that within command.c knows the internals of the key.

For RSA (and current implementation) it will be:

- type: KEY-DATA
  value: hex(n)
- type: KEY-DATA
  value: hex(e)

Not sure how we transmit the key type, but what I would like to achieve is a command.c which gets this list, iterate it and send it over the assuan socket without actually knows what the key type is.

@rkeene
Copy link
Contributor Author

rkeene commented Oct 18, 2022

I refactored the code.

@rkeene
Copy link
Contributor Author

rkeene commented Oct 18, 2022

@alonbl I'm trying to add GENKEY support now. Do you know where it's documented for RSA and ECC ? e.g., sending KEY-DATA with n and e for RSA -- where is that specified ?

I'm guessing that something similar needs to be done for EcDSA for q and curve, but do we also need to specify that ECC is being used and not RSA ?

@rkeene
Copy link
Contributor Author

rkeene commented Oct 18, 2022

Based on some postings I found online, it looks like the "KEY-DATA" for "q" (as hex-encoded integer) and "curve" as DER-encoded OID (minus tag) is what's needed.

@rkeene
Copy link
Contributor Author

rkeene commented Oct 19, 2022

This functionality is almost entirely working:

gpg: key 10ECAD2B69B1E2E3 marked as ultimately trusted
gpg: directory '/home/rkeene/.gnupg/openpgp-revocs.d' created
gpg: error reading rest of packet: Invalid argument
gpg: can't encode a 512 bit MD into a 72 bits frame, algo=10
gpg: revocation certificate stored as '/home/rkeene/.gnupg/openpgp-revocs.d/3AAF050CCCE2EE667BDAB3D010ECAD2B69B1E2E3.rev'
public and secret key created and signed.

gpg: can't encode a 512 bit MD into a 72 bits frame, algo=10
pub   nistp256 2022-10-19 [INVALID_ALGO]
      3AAF050CCCE2EE667BDAB3D010ECAD2B69B1E2E3
uid                      xxxxx <x@x.com>

@rkeene
Copy link
Contributor Author

rkeene commented Oct 19, 2022

I think the remaining issues are with cmd_getattr(), but it's not clear why some of the things being done are being done there, especially KEY-ATTR and EXTCAP which mention 2048 (which I assume is a reference to the RSA key size).

In KEY-ATTR there's a loop of size 3 but why isn't clear either.

@rkeene
Copy link
Contributor Author

rkeene commented Oct 26, 2022

I'm back to this -- do you have have any ideas @alonbl ? Otherwise I'm going to have to dig through the GPG code.

@alonbl
Copy link
Owner

alonbl commented Oct 29, 2022

I'm back to this -- do you have have any ideas @alonbl ? Otherwise I'm going to have to dig through the GPG code.

You will need to reverse engineer gnupg own scd and see what you get for each case. As there is no formal spec for the IPC this is the only way to make it work.

Copy link
Owner

@alonbl alonbl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
In order to push this forward, please prepare a set of pull requests of cleanups, each per something we can quickly merge, so that it will be simpler to digest the remaining EC only related additions.

@@ -30,6 +30,7 @@

#include "common.h"
#include "strgetopt.h"
#include <pkcs11-helper-1.0/pkcs11.h>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this required?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this for things like CKR_OK because it wasn't clear it would otherwise be included.

gnupg-pkcs11-scd/command.c Outdated Show resolved Hide resolved
gnupg-pkcs11-scd/command.c Outdated Show resolved Hide resolved
}

if (_pkcs11_keyinfo_mechanism(keyinfo, &pkcs11_mechanism) != CKR_OK) {
goto cleanup;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please focus in EC in this thread, any other change such as rename of the variables or modifying any behavior should go to other pull request.

In this case you assume that the problem is something within the token to select the hash, while as far as I remember the gnupg is the one that decides in some cases to pass the entire blob forcing us to guess what hash did he wish use to use.

anyway, in order to discuss it better please move this into other pull request.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you mean.

The highlighted change is regarding selecting the mechanism for asking the PKCS#11 module to sign using the correct mechanism, as well as ensuring PKCS padding is only used when using (CKM_RSA_PKCS)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I do not understand the code, this is why it is better to do this in steps each change own pull request...

gnupg provides data which may or may not include the hash packaging, the fixup should be done in any case.

you assume that this fixup should be done only if key type is rsa, correct? have you looked at the scd sources to see if this is correct and hash never provided in this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The encoding specified by PKCS#1 would only be there for RSA -- EcDSA keys simply aren't large enough.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't ec also signs hashes? as far as I know it does. how will the peer know what hash was used in the signature? the hash name/oid must be signed as well for this to be secure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EcDSA keys for NIST P-256 are 33 bytes (257 bits) long (in compressed mode) with 64 byte signatures.

The CKM_ECDSA mechanism expects the input to already be hashed (https://www.cryptsoft.com/pkcs11doc/v220/group__SEC__12__3__6__ECDSA__WITHOUT__HASHING.html) and encoded to fit within 2*keyLength.

The padding/encoding for PKCS#1 isn't needed since the keys are so much smaller.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the digest algorithm id is not signed then I may modify the digest id in the unauthenticated message to less secure digest that its value matches the more secure so validate process will validate less secure digest without being aware of the switch. anyway, it is not that important as long as if you sign the gnupg peer will be able to verify.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code now removes any found prefix.

gnupg-pkcs11-scd/command.c Outdated Show resolved Hide resolved
gnupg-pkcs11-scd/command.c Show resolved Hide resolved
gnupg-pkcs11-scd/keyutil.c Outdated Show resolved Hide resolved
Copy link
Contributor

@invidian invidian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @rkeene, having support for ec25519/ecdsa keys would be really awesome.

@rkeene
Copy link
Contributor Author

rkeene commented Oct 31, 2022

You will need to reverse engineer gnupg own scd and see what you get for each case. As there is no formal spec for the IPC this is the only way to make it work.

I'm almost done with this.

gnupg-pkcs11-scd/command.c Outdated Show resolved Hide resolved
use_pkcs1 = 1;
break;
case CKM_ECDSA:
use_pkcs1 = 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need this variable? can't you ask below if mechanism is RSA_PKCS?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future there may be other mechanisms that do or do not use PKCS#1 padding.

}

if (_pkcs11_keyinfo_mechanism(keyinfo, &pkcs11_mechanism) != CKR_OK) {
goto cleanup;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I do not understand the code, this is why it is better to do this in steps each change own pull request...

gnupg provides data which may or may not include the hash packaging, the fixup should be done in any case.

you assume that this fixup should be done only if key type is rsa, correct? have you looked at the scd sources to see if this is correct and hash never provided in this case?

@rkeene
Copy link
Contributor Author

rkeene commented Nov 1, 2022

I'm making progress here, creating subkeys is working but signing is not yet working.

$ gpg --list-secret-keys
gpg: NOTE: THIS IS A DEVELOPMENT VERSION!
gpg: It is only intended for test purposes and should NOT be
gpg: used in a production environment or with production keys!
/home/rkeene/.gnupg/pubring.kbx
-------------------------------
sec#  nistp256 2022-10-31 [SCA]
      F053661CDB471F87D9D7C31B158A385D4B4ECDA7
uid           [ultimate] xxxxx <x@x.com>

$ echo test | gpg --clear-sign F053661CDB471F87D9D7C31B158A385D4B4ECDA7
gpg: NOTE: THIS IS A DEVELOPMENT VERSION!
gpg: It is only intended for test purposes and should NOT be
gpg: used in a production environment or with production keys!
gpg: no default secret key: Unusable secret key
gpg: F053661CDB471F87D9D7C31B158A385D4B4ECDA7: clear-sign failed: Unusable secret key

There are bugs in GPG when dealing with EcDSA keys that reside on cards.

@alonbl
Copy link
Owner

alonbl commented Nov 1, 2022

There are bugs in GPG when dealing with EcDSA keys that reside on cards.

there usually are... very frustrating to chase non-standard non-cooperative undocumented unstable proprietary non-modular project to provide standard interface.

thank your help, in the meanwhile I think you have done many good cleanups, if we review them one by one we may reach to a point in which the EC part will be left more or less ready until gnupg support will be sorted out.

@rkeene
Copy link
Contributor Author

rkeene commented Nov 2, 2022

This appears to be working now.

$ gpg --expert --full-generate-key
gpg (GnuPG) 2.3.2-beta105; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: NOTE: THIS IS A DEVELOPMENT VERSION!
gpg: It is only intended for test purposes and should NOT be
gpg: used in a production environment or with production keys!
gpg: keybox '/home/rkeene/.gnupg/pubring.kbx' created
Please select what kind of key you want:
   (1) RSA and RSA
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
   (9) ECC (sign and encrypt) *default*
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (13) Existing key
  (14) Existing key from card
Your selection? 13
Enter the keygrip: F8BC7DE50508E0C578EE5F60021EB57B46D7F22B
                                                           
Possible actions for this ECC key: Sign Certify Authenticate 
Current allowed actions: Sign Certify 

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

> q
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years

> 0
Key does not expire at all
                        
GnuPG needs to construct a user ID to identify your key.

You selected this USER-ID:
    "xxxxxx <x@x.com>"

gpg: key FDE693371D5E0761 marked as ultimately trusted
gpg: revocation certificate stored as '/home/rkeene/.gnupg/openpgp-revocs.d/A5A3AE53DE9E0D69CDC98C60FDE693371D5E0761.rev'
public and secret key created and signed.

pub   nistp256 2022-11-02 [SC]
      A5A3AE53DE9E0D69CDC98C60FDE693371D5E0761
uid                      xxxxxx <x@x.com>


$ gpg --check-signatures
/home/rkeene/.gnupg/pubring.kbx
-------------------------------
pub   nistp256 2022-11-02 [SC]
      A5A3AE53DE9E0D69CDC98C60FDE693371D5E0761
uid           [ultimate] xxxxxx <x@x.com>
sig!3        FDE693371D5E0761 2022-11-02  xxxxxx <x@x.com>

gpg: 1 good signature


$ echo 'test' | gpg --clear-sign
gpg: NOTE: THIS IS A DEVELOPMENT VERSION!
gpg: It is only intended for test purposes and should NOT be
gpg: used in a production environment or with production keys!
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

test
-----BEGIN PGP SIGNATURE-----

iHUEARMIAB0WIQSlo65T3p4Nac3JjGD95pM3HV4HYQUCY2HWxgAKCRD95pM3HV4H
YWvfAQDZ0ov5/NZxJf6eDrx76uDQ3qnXAKY6EBpbLq0k1+YKVAD/bV52WO8uFtSW
1oq+Fe4jQWCBNnrMmRFA+NRaMwRYs8Q=
=EidH
-----END PGP SIGNATURE-----


$ gpg --verify
...
gpg: Signature made Tue 01 Nov 2022 09:32:38 PM CDT
gpg:                using ECDSA key A5A3AE53DE9E0D69CDC98C60FDE693371D5E0761
gpg: Good signature from "xxxxxx <x@x.com>" [ultimate]

@rkeene rkeene requested a review from alonbl November 2, 2022 03:06
@rkeene rkeene marked this pull request as ready for review November 2, 2022 03:07
@rkeene
Copy link
Contributor Author

rkeene commented Nov 2, 2022

GPG Patch added to this bug report: https://dev.gnupg.org/T5555

@rkeene rkeene marked this pull request as draft November 2, 2022 20:44
@alonbl
Copy link
Owner

alonbl commented Nov 2, 2022 via email

@rkeene
Copy link
Contributor Author

rkeene commented Nov 3, 2022

@alonbl There aren't any trivial renames as part of this PR aside from the refactor of "keyutil" leading to keyutil_get_cert_hexgrip being renamed to keyinfo_get_hexgrip

@rkeene
Copy link
Contributor Author

rkeene commented Nov 3, 2022

I've created PRs #48, #49, and #50 with bug fixes, #51 with a refactor that enables multiple kinds of keys, and #52 which adds support for signing of keys which do not use PKCS1 encoding.

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

Successfully merging this pull request may close these issues.

3 participants