-
Notifications
You must be signed in to change notification settings - Fork 32
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
RSA Signing & Verification Support #35
Conversation
OK, that's it. I think this is ready for a thorough review, after handling importing RSA keys & certificates for singing and verification respectively, with a good amount unit tests for all sorts of variations. |
src/Key.php
Outdated
$this->secret = $item; | ||
$publicKey = null; | ||
$privateKey = null; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like you're specifying a very different representation of a key here - if the implementation is so different I'd suggest the concrete types be split out and use a common interface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This took me ages to decide on. I wasn't happy just inventing a new architectural component, and burdening the user with having to understand the various key types with explicit calls. This implementation doesn't break existing flows, and automagically sorts the asymmetric types to handle the sign() and verify() flows (which don't differ in the hmac case).
Acknowledged this is not a complete implementation, but is that preferred over compatibility and user experience?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're looking at an overhaul of the Key type and KeyStore, should we incorporate #18 for the KeyStore itself? Or maybe handle the proposed work under that issue in the future and implement this solution for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK so I'd suggest approaching this a little bit differently. Keep the single concrete Key
and keep it a simple representation of the Key. Ensure your secret is a string only - mixed use variables are a pain IMO. Remove the public variables but expose a
public function isRSAPrivateKey()
public function isX509Certificate()
Then in Verification
and *Algorithm
put the actual logic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For RSA there is no one "key", there is a signing key (private) and a verification key (public), so we need to handle these. Keep the internal representation but private, expose them via functions as you describe? Oh, and a certificate is just a container for a public key, we should use/expose it directly for consistency.
public function getRSAPublicKey()
public function getRSAPrivateKey()
public function getHmacSecret()
For EC (in the future) add:
public function getECPublicKey()
public function getECPrivateKey()
And with key overhaul to handle rotation in #18 (also future):
public function getRSAPublicKeys($keyId)
public function getECPublicKeys($keyId)
public function getHmacSecrets($keyId)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any further comments here? |
Can you rebase and remove the merge commits? |
Hey @liamdennehy I'm not sure you're following my request regarding the rebase, so will try be more clear :) We follow a "feature branch" or "Github Flow" workflow. So:
|
@mtibben There's a strong possibility I have no idea what I'm doing |
* Specification does not permit other hash algorithms for RSA signatures
@@ -34,9 +37,8 @@ public function __construct($args) | |||
|
|||
// algorithm for signing; not necessary for verifying. | |||
if (isset($args['algorithm'])) { | |||
$this->algorithmName = $args['algorithm']; | |||
$this->algorithm = Algorithm::create($args['algorithm']); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This old parameter only handled the HMAC case, where a signing and verifying key are the same. Needed a class to discriminate HMAC from RSA, so invoke with a factory that makes the right underlying Algorithm subclass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mtibben Still new to OO, is this a good approach?
|
||
private function getRSAPrivateKey($object) | ||
{ | ||
if (is_array($object)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under what circumstances is this going to be an array and why? Ideally avoid allowing multiple types in arguments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user either supplies:
- A Public Key/Certificate for verifying as string/object
- A Private Key for signing as string/object
- Or both together in an array of string/objects - this can now be used for both signing and verifying without having to construct different objects for each case.
Allowing both forms means we can use the same KeyStore object for all three cases to derive a Key object. Alternative is to expose HMAC and Asymmetric-specific Key interfaces which is both a BC and requires more documentation and user education for little gain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mtibben Is this ok? I realise the input here is fungible, but I'd rather that than expect the user to do key/certificate handling to a more advanced degree.
@mtibben I'm going to overhaul the Key class to make the flow easier to track, eg static function hasX509Certificate($object) ...to explicitly test if an object has a certificate instead of try..catch blocks all over the place. This will also make a good base to extend the class for #18 (Key Rotation). Will ping you when it's ready. |
* Key now handles inputs as X.509, naked Public Key and Private Key (all PEM) * Improved & clearer detection logic with explicit tests for asymmetric key material, falling back on shared secret for HMAC if asymmetric keys are not detected hasX509Certificate() hasPublicKey() hasPrivateKey() * Clearer names for test constants (easier to expand to EC later)
Any further questions, or updates on open conversations in this PR? |
Hello, Can you please merge and tag this PR ? Regards, Arnaud |
Apologies, accidentally deleted the branch for this PR in my source. However, I have integrated this feature in my own project along with a number of others, and published this in packagist. Documentation for the entire library is published at Read the Docs: http-signatures-php - incomplete but being expanded regularly. |
- Remove unsupported Symfony/PHP version combinations - Add PHP 7.3 support
Closing PR due to inactivity. |
RSA signing is largely similar to hmac, both requiring a secret (shared in the hmac case), but the difference in key material for signing is significant. Verification is very different, so not trivial to extend.
This PR adds:
algorithm
field, and selecting the right hash algorithm (could be replaced on detection of supplied key?)keyId
and use a X.509 certificate instead of a secret/privateKey.